From 62606d283ee82437c555dc7489a9a9ea36a826c8 Mon Sep 17 00:00:00 2001 From: jamesharrow <93921463+jamesharrow@users.noreply.github.com> Date: Mon, 18 Dec 2023 12:48:23 +0000 Subject: [PATCH 1/8] [EVSE] add evse cluster and examples energy management app (#30793) * Fix #30665 (EVSE) - Changed to use amperage_mA, energy_mWh - removed max on epoch_s - removed access for operate - removed side for events * Fix #30665 updates to try to get further with ZAP and autogen, but still fails with some parts of regen_all * Added ember-compatibility-functions.cpp which was missing. * Made all types all lowercase to resolve regen_all issues. * Fixed lint issue (trailing whitespace). * Fixes #30727 - Added initial EVSE cluster and Example Energy Managament app. * Tidied up old comments. * Restyled by whitespace * Restyled by gn * Restyled by prettier-markdown * Added copy of files to all-clusters-app linux BUILD.gn and did basic test with chip-tool * Fixed lint error (Remove PRId64) * Fix for Documentation Build and publish checker. * Updated all-clusters-app.zap after merge and regen_all * Added Cluster to ESP32 CMakeLists.txt * Fixed ESP32 compile error caused by %d * Added missing source files to each build variant * Restyled by gn * Fixed incorrect uint64_t in EnableCharging/EnableDischarging command * Fixed more issues seen on different platforms * Removed unused mEndpointId * Add source files to shell standalone BUILD.gn, More %d fixes for different platforms * Restyled by gn * Removed unused mMinimumChargingCurrentLimitFromCommand * Removed yet more unused variables * Fixed missing semi-colon. How did the other compilers not pick this up? * Capitalise function names * PR comment - Moved PluginServerInitCallback to sdk. Capitalised more function names in energy-management-app. * Restyled by whitespace * Fixes #30805 Updated energy-evse-cluster.xml * Fixes #30805 zap_regen_all commit. * Made Fault Event allow a nullable SessionID * Updates based on review (use kMaximumChargeCurrent instead of duplicate #define). Add HwSetVehicleID implementation * Added RFID Event support. Removed more unnecessary chip:: * Added Feature flags, optional commands and optional attributes. * Made command handling conditional based on features * Added Feature support to all-clusters-app * Restyled by clang-format * Fix to Darwin compile error - not checking strcmp return * Attempt to fix Darwin errors (return after else) * Updated based on latest upstream master * Removed unnecessary mInstance and used 'this' instead. * Regen_all after merge to master. * Fix review comment. * Ensure Init() returns a failure if there is one. Aligned to mode-base-server.cpp * Backed out Read attr check based on features. * Fixed EnumerateAcceptedCommands to handle Loop::Break condition. * Had missed StartDiagnostic as an optional command in InvokeCommand * Removed extra chip:: in attr types. * Updated HwSetVehicleID to copy the value from callee * Fixed potential buffer overrun in HwSetVehicleID. * Fixed simple to address comments raised by Andrei in PR 30857 * Check Delegate is initialized before calling functions. * Ensured that mVehicleID free's any malloc'd CharSpan in destructor * Sync EnergyEvseDelegateImpl.cpp from Example Energy Management * Re-write of ApplicationInit to handle potential errors * Open and saved in ZAP, then regen_all * Updated Energy-management-app.zap / .matter after change to general-diagnostics.xml change to MS. * Fixed types to be signed=true * Fixed 31032 - revert removal of side="server". Also turned on Events. * PR comment fix - remove Localization Config and Time Format Localization cluster --------- Co-authored-by: Restyled.io --- docs/examples/index.md | 9 + .../all-clusters-common/all-clusters-app.zap | 8 +- .../energy-management-common/BUILD.gn | 29 + .../energy-management-app.matter | 1343 +++++++ .../energy-management-app.zap | 3157 +++++++++++++++++ .../include/EVSEManufacturerImpl.h | 52 + .../include/EnergyEvseDelegateImpl.h | 196 + .../include/EnergyEvseManager.h | 57 + .../include/EnergyManagementManager.h | 26 + .../src/EVSEManufacturerImpl.cpp | 69 + .../src/EnergyEvseDelegateImpl.cpp | 793 +++++ .../src/EnergyEvseManager.cpp | 33 + .../src/EnergyManagementManager.cpp | 18 + examples/energy-management-app/linux/.gn | 25 + examples/energy-management-app/linux/BUILD.gn | 125 + .../energy-management-app/linux/README.md | 143 + examples/energy-management-app/linux/args.gni | 31 + .../linux/build_overrides | 1 + .../linux/include/CHIPProjectAppConfig.h | 49 + examples/energy-management-app/linux/main.cpp | 144 + .../linux/third_party/connectedhomeip | 1 + .../zcl/data-model/chip/chip-types.xml | 8 +- .../data-model/chip/energy-evse-cluster.xml | 12 +- .../zap-generated/cluster/Commands.h | 32 +- .../zap-generated/cluster/Commands.h | 8 +- 25 files changed, 6336 insertions(+), 33 deletions(-) create mode 100644 examples/energy-management-app/energy-management-common/BUILD.gn create mode 100644 examples/energy-management-app/energy-management-common/energy-management-app.matter create mode 100644 examples/energy-management-app/energy-management-common/energy-management-app.zap create mode 100644 examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h create mode 100644 examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h create mode 100644 examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h create mode 100644 examples/energy-management-app/energy-management-common/include/EnergyManagementManager.h create mode 100644 examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp create mode 100644 examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp create mode 100644 examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp create mode 100644 examples/energy-management-app/energy-management-common/src/EnergyManagementManager.cpp create mode 100644 examples/energy-management-app/linux/.gn create mode 100644 examples/energy-management-app/linux/BUILD.gn create mode 100644 examples/energy-management-app/linux/README.md create mode 100644 examples/energy-management-app/linux/args.gni create mode 120000 examples/energy-management-app/linux/build_overrides create mode 100644 examples/energy-management-app/linux/include/CHIPProjectAppConfig.h create mode 100644 examples/energy-management-app/linux/main.cpp create mode 120000 examples/energy-management-app/linux/third_party/connectedhomeip diff --git a/docs/examples/index.md b/docs/examples/index.md index 926106be0490d8..e31b434515f11b 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -78,6 +78,15 @@ chip-tool/README darwin-framework-tool/README ``` +## Energy Management example + +```{toctree} +:glob: +:maxdepth: 1 + +energy-management-app/**/README +``` + ## Java matter controller example ```{toctree} diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index 69c6f8ec0cb8de..0bba4b8871e6c2 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -12148,7 +12148,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -12164,7 +12164,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -12180,7 +12180,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -12196,7 +12196,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, diff --git a/examples/energy-management-app/energy-management-common/BUILD.gn b/examples/energy-management-app/energy-management-common/BUILD.gn new file mode 100644 index 00000000000000..7c2040c1a4dc37 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/BUILD.gn @@ -0,0 +1,29 @@ +# 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}/examples/common/pigweed/pigweed_rpcs.gni") +import("${chip_root}/src/app/chip_data_model.gni") + +config("config") { + include_dirs = [ "include" ] +} + +chip_data_model("energy-management-common") { + zap_file = "energy-management-app.zap" + + zap_pregenerated_dir = + "${chip_root}/zzz_generated/energy-management-app/zap-generated" + is_server = true +} diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.matter b/examples/energy-management-app/energy-management-common/energy-management-app.matter new file mode 100644 index 00000000000000..0452ec58d3eef8 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/energy-management-app.matter @@ -0,0 +1,1343 @@ +// This IDL was generated automatically by ZAP. +// It is for view/code review purposes only. + +/** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ +cluster Identify = 3 { + revision 4; + + 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 description for Identify */ + command access(invoke: manage) Identify(IdentifyRequest): DefaultSuccess = 0; + /** Command description for TriggerEffect */ + command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64; +} + +/** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ +cluster Descriptor = 29 { + revision 2; + + bitmap Feature : bitmap32 { + kTagList = 0x1; + } + + struct DeviceTypeStruct { + devtype_id deviceType = 0; + int16u revision = 1; + } + + struct SemanticTagStruct { + nullable vendor_id mfgCode = 0; + enum8 namespaceID = 1; + enum8 tag = 2; + optional nullable char_string label = 3; + } + + 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 optional SemanticTagStruct tagList[] = 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; +} + +/** 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. */ +cluster AccessControl = 31 { + revision 1; // NOTE: Default/not specifically set + + 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) optional 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. */ +cluster BasicInformation = 40 { + revision 3; + + 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 optional char_string<16> manufacturingDate = 11; + readonly attribute optional char_string<32> partNumber = 12; + readonly attribute optional long_char_string<256> productURL = 13; + readonly attribute optional char_string<64> productLabel = 14; + readonly attribute optional char_string<32> serialNumber = 15; + attribute access(write: manage) optional boolean localConfigDisabled = 16; + readonly attribute optional boolean reachable = 17; + readonly attribute optional char_string<32> uniqueID = 18; + readonly attribute CapabilityMinimaStruct capabilityMinima = 19; + readonly attribute optional ProductAppearanceStruct productAppearance = 20; + readonly attribute int32u specificationVersion = 21; + readonly attribute int16u maxPathsPerInvoke = 22; + 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 MfgSpecificPing(): DefaultSuccess = 0; +} + +/** 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. */ +cluster UnitLocalization = 45 { + revision 1; + + enum TempUnitEnum : enum8 { + kFahrenheit = 0; + kCelsius = 1; + kKelvin = 2; + } + + bitmap Feature : bitmap32 { + kTemperatureUnit = 0x1; + } + + attribute access(write: manage) optional 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. */ +cluster GeneralCommissioning = 48 { + revision 1; // NOTE: Default/not specifically set + + 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; + } + + response struct ArmFailSafeResponse = 1 { + CommissioningErrorEnum errorCode = 0; + char_string<128> debugText = 1; + } + + request struct SetRegulatoryConfigRequest { + RegulatoryLocationTypeEnum newRegulatoryConfig = 0; + char_string<2> countryCode = 1; + int64u breadcrumb = 2; + } + + response struct SetRegulatoryConfigResponse = 3 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + response struct CommissioningCompleteResponse = 5 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + /** Arm the persistent fail-safe timer with an expiry time of now + ExpiryLengthSeconds using device clock */ + command access(invoke: administer) ArmFailSafe(ArmFailSafeRequest): ArmFailSafeResponse = 0; + /** Set the regulatory configuration to be used during commissioning */ + command access(invoke: administer) SetRegulatoryConfig(SetRegulatoryConfigRequest): SetRegulatoryConfigResponse = 2; + /** Signals the Server that the Client has successfully completed all steps of Commissioning/Recofiguration needed during fail-safe period. */ + fabric command access(invoke: administer) CommissioningComplete(): CommissioningCompleteResponse = 4; +} + +/** Functionality to configure, enable, disable network credentials and access on a Matter device. */ +cluster NetworkCommissioning = 49 { + revision 1; // NOTE: Default/not specifically set + + 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; + kPerDeviceCredentials = 0x8; + } + + bitmap ThreadCapabilitiesBitmap : bitmap16 { + kIsBorderRouterCapable = 0x1; + kIsRouterCapable = 0x2; + kIsSleepyEndDeviceCapable = 0x4; + kIsFullThreadDevice = 0x8; + kIsSynchronizedSleepyEndDeviceCapable = 0x10; + } + + bitmap WiFiSecurityBitmap : bitmap8 { + kUnencrypted = 0x1; + kWEP = 0x2; + kWPAPersonal = 0x4; + kWPA2Personal = 0x8; + kWPA3Personal = 0x10; + kWPA3MatterPDC = 0x20; + } + + struct NetworkInfoStruct { + octet_string<32> networkID = 0; + boolean connected = 1; + optional nullable octet_string<20> networkIdentifier = 2; + optional nullable octet_string<20> clientIdentifier = 3; + } + + 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 optional int8u scanMaxTimeSeconds = 2; + readonly attribute optional 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 optional WiFiBandEnum supportedWiFiBands[] = 8; + readonly attribute optional ThreadCapabilitiesBitmap supportedThreadFeatures = 9; + readonly attribute optional int16u threadVersion = 10; + 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; + } + + response struct ScanNetworksResponse = 1 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + optional WiFiInterfaceScanResultStruct wiFiScanResults[] = 2; + optional ThreadInterfaceScanResultStruct threadScanResults[] = 3; + } + + request struct AddOrUpdateWiFiNetworkRequest { + octet_string<32> ssid = 0; + octet_string<64> credentials = 1; + optional int64u breadcrumb = 2; + optional octet_string<140> networkIdentity = 3; + optional octet_string<20> clientIdentifier = 4; + optional octet_string<32> possessionNonce = 5; + } + + request struct AddOrUpdateThreadNetworkRequest { + octet_string<254> operationalDataset = 0; + optional int64u breadcrumb = 1; + } + + request struct RemoveNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct NetworkConfigResponse = 5 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string<512> debugText = 1; + optional int8u networkIndex = 2; + optional octet_string<140> clientIdentity = 3; + optional octet_string<64> possessionSignature = 4; + } + + request struct ConnectNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct ConnectNetworkResponse = 7 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + nullable int32s errorValue = 2; + } + + request struct ReorderNetworkRequest { + octet_string<32> networkID = 0; + int8u networkIndex = 1; + optional int64u breadcrumb = 2; + } + + request struct QueryIdentityRequest { + octet_string<20> keyIdentifier = 0; + optional octet_string<32> possessionNonce = 1; + } + + response struct QueryIdentityResponse = 10 { + octet_string<140> identity = 0; + optional octet_string<64> possessionSignature = 1; + } + + /** Detemine the set of networks the device sees as available. */ + command access(invoke: administer) ScanNetworks(ScanNetworksRequest): ScanNetworksResponse = 0; + /** Add or update the credentials for a given Wi-Fi network. */ + command access(invoke: administer) AddOrUpdateWiFiNetwork(AddOrUpdateWiFiNetworkRequest): NetworkConfigResponse = 2; + /** Add or update the credentials for a given Thread network. */ + command access(invoke: administer) AddOrUpdateThreadNetwork(AddOrUpdateThreadNetworkRequest): NetworkConfigResponse = 3; + /** Remove the definition of a given network (including its credentials). */ + command access(invoke: administer) RemoveNetwork(RemoveNetworkRequest): NetworkConfigResponse = 4; + /** Connect to the specified network, using previously-defined credentials. */ + command access(invoke: administer) ConnectNetwork(ConnectNetworkRequest): ConnectNetworkResponse = 6; + /** Modify the order in which networks will be presented in the Networks attribute. */ + command access(invoke: administer) ReorderNetwork(ReorderNetworkRequest): NetworkConfigResponse = 8; + /** Retrieve details about and optionally proof of possession of a network client identity. */ + command access(invoke: administer) QueryIdentity(QueryIdentityRequest): QueryIdentityResponse = 9; +} + +/** 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. */ +cluster GeneralDiagnostics = 51 { + revision 2; + + 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 optional int64u upTime = 2; + readonly attribute optional int32u totalOperationalHours = 3; + readonly attribute optional BootReasonEnum bootReason = 4; + readonly attribute optional HardwareFaultEnum activeHardwareFaults[] = 5; + readonly attribute optional RadioFaultEnum activeRadioFaults[] = 6; + readonly attribute optional 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; + } + + response struct TimeSnapshotResponse = 2 { + systime_ms systemTimeMs = 0; + nullable posix_ms posixTimeMs = 1; + } + + /** Provide a means for certification tests to trigger some test-plan-specific events */ + command access(invoke: manage) TestEventTrigger(TestEventTriggerRequest): DefaultSuccess = 0; + /** Take a snapshot of system time and epoch time. */ + command TimeSnapshot(): TimeSnapshotResponse = 1; +} + +/** Commands to trigger a Node to allow a new Administrator to commission it. */ +cluster AdministratorCommissioning = 60 { + revision 1; // NOTE: Default/not specifically set + + enum CommissioningWindowStatusEnum : enum8 { + kWindowNotOpen = 0; + kEnhancedWindowOpen = 1; + kBasicWindowOpen = 2; + } + + enum StatusCode : enum8 { + kBusy = 2; + kPAKEParameterError = 3; + kWindowNotOpen = 4; + } + + bitmap Feature : bitmap32 { + kBasic = 0x1; + } + + readonly attribute CommissioningWindowStatusEnum windowStatus = 0; + readonly attribute nullable fabric_idx adminFabricIndex = 1; + readonly attribute nullable vendor_id 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<32> salt = 4; + } + + request struct OpenBasicCommissioningWindowRequest { + int16u commissioningTimeout = 0; + } + + /** This command is used by a current Administrator to instruct a Node to go into commissioning mode using enhanced commissioning method. */ + timed command access(invoke: administer) OpenCommissioningWindow(OpenCommissioningWindowRequest): DefaultSuccess = 0; + /** This command is used by a current Administrator to instruct a Node to go into commissioning mode using basic commissioning method, if the node supports it. */ + timed command access(invoke: administer) OpenBasicCommissioningWindow(OpenBasicCommissioningWindowRequest): DefaultSuccess = 1; + /** This command is used by a current Administrator to instruct a Node to revoke any active Open Commissioning Window or Open Basic Commissioning Window command. */ + 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. */ +cluster OperationalCredentials = 62 { + revision 1; // NOTE: Default/not specifically set + + 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<32> attestationNonce = 0; + } + + response struct AttestationResponse = 1 { + octet_string<900> attestationElements = 0; + octet_string<64> attestationSignature = 1; + } + + request struct CertificateChainRequestRequest { + CertificateChainTypeEnum certificateType = 0; + } + + response struct CertificateChainResponse = 3 { + octet_string<600> certificate = 0; + } + + request struct CSRRequestRequest { + octet_string<32> CSRNonce = 0; + optional boolean isForUpdateNOC = 1; + } + + response struct CSRResponse = 5 { + octet_string NOCSRElements = 0; + octet_string attestationSignature = 1; + } + + request struct AddNOCRequest { + octet_string<400> NOCValue = 0; + optional octet_string<400> ICACValue = 1; + octet_string<16> IPKValue = 2; + int64u caseAdminSubject = 3; + vendor_id adminVendorId = 4; + } + + request struct UpdateNOCRequest { + octet_string NOCValue = 0; + optional octet_string ICACValue = 1; + } + + response struct NOCResponse = 8 { + NodeOperationalCertStatusEnum statusCode = 0; + optional fabric_idx fabricIndex = 1; + optional char_string<128> debugText = 2; + } + + request struct UpdateFabricLabelRequest { + char_string<32> label = 0; + } + + request struct RemoveFabricRequest { + fabric_idx fabricIndex = 0; + } + + request struct AddTrustedRootCertificateRequest { + octet_string rootCACertificate = 0; + } + + /** Sender is requesting attestation information from the receiver. */ + command access(invoke: administer) AttestationRequest(AttestationRequestRequest): AttestationResponse = 0; + /** Sender is requesting a device attestation certificate from the receiver. */ + command access(invoke: administer) CertificateChainRequest(CertificateChainRequestRequest): CertificateChainResponse = 2; + /** Sender is requesting a certificate signing request (CSR) from the receiver. */ + command access(invoke: administer) CSRRequest(CSRRequestRequest): CSRResponse = 4; + /** Sender is requesting to add the new node operational certificates. */ + command access(invoke: administer) AddNOC(AddNOCRequest): NOCResponse = 6; + /** Sender is requesting to update the node operational certificates. */ + fabric command access(invoke: administer) UpdateNOC(UpdateNOCRequest): NOCResponse = 7; + /** This command SHALL be used by an Administrative Node to set the user-visible Label field for a given Fabric, as reflected by entries in the Fabrics attribute. */ + fabric command access(invoke: administer) UpdateFabricLabel(UpdateFabricLabelRequest): NOCResponse = 9; + /** This command is used by Administrative Nodes to remove a given fabric index and delete all associated fabric-scoped data. */ + command access(invoke: administer) RemoveFabric(RemoveFabricRequest): NOCResponse = 10; + /** This command SHALL add a Trusted Root CA Certificate, provided as its CHIP Certificate representation. */ + command access(invoke: administer) AddTrustedRootCertificate(AddTrustedRootCertificateRequest): DefaultSuccess = 11; +} + +/** The Group Key Management Cluster is the mechanism by which group keys are managed. */ +cluster GroupKeyManagement = 63 { + revision 1; // NOTE: Default/not specifically set + + enum GroupKeySecurityPolicyEnum : enum8 { + kTrustFirst = 0; + kCacheAndSync = 1; + } + + bitmap Feature : bitmap32 { + kCacheAndSync = 0x1; + } + + 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; + } + + response struct KeySetReadResponse = 2 { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetRemoveRequest { + int16u groupKeySetID = 0; + } + + response struct KeySetReadAllIndicesResponse = 5 { + int16u groupKeySetIDs[] = 0; + } + + /** Write a new set of keys for the given key set id. */ + fabric command access(invoke: administer) KeySetWrite(KeySetWriteRequest): DefaultSuccess = 0; + /** Read the keys for a given key set id. */ + fabric command access(invoke: administer) KeySetRead(KeySetReadRequest): KeySetReadResponse = 1; + /** Revoke a Root Key from a Group */ + fabric command access(invoke: administer) KeySetRemove(KeySetRemoveRequest): DefaultSuccess = 3; + /** Return the list of Group Key Sets associated with the accessing fabric */ + fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4; +} + +/** Electric Vehicle Supply Equipment (EVSE) is equipment used to charge an Electric Vehicle (EV) or Plug-In Hybrid Electric Vehicle. This cluster provides an interface to the functionality of Electric Vehicle Supply Equipment (EVSE) management. */ +provisional cluster EnergyEvse = 153 { + revision 1; // NOTE: Default/not specifically set + + enum EnergyTransferStoppedReasonEnum : enum8 { + kEVStopped = 0; + kEVSEStopped = 1; + kOther = 2; + } + + enum FaultStateEnum : enum8 { + kNoError = 0; + kMeterFailure = 1; + kOverVoltage = 2; + kUnderVoltage = 3; + kOverCurrent = 4; + kContactWetFailure = 5; + kContactDryFailure = 6; + kGroundFault = 7; + kPowerLoss = 8; + kPowerQuality = 9; + kPilotShortCircuit = 10; + kEmergencyStop = 11; + kEVDisconnected = 12; + kWrongPowerSupply = 13; + kLiveNeutralSwap = 14; + kOverTemperature = 15; + kOther = 255; + } + + enum StateEnum : enum8 { + kNotPluggedIn = 0; + kPluggedInNoDemand = 1; + kPluggedInDemand = 2; + kPluggedInCharging = 3; + kPluggedInDischarging = 4; + kSessionEnding = 5; + kFault = 6; + } + + enum SupplyStateEnum : enum8 { + kDisabled = 0; + kChargingEnabled = 1; + kDischargingEnabled = 2; + kDisabledError = 3; + kDisabledDiagnostics = 4; + } + + bitmap Feature : bitmap32 { + kChargingPreferences = 0x1; + kSoCReporting = 0x2; + kPlugAndCharge = 0x4; + kRFID = 0x8; + kV2X = 0x10; + } + + bitmap TargetDayOfWeekBitmap : bitmap8 { + kSunday = 0x1; + kMonday = 0x2; + kTuesday = 0x4; + kWednesday = 0x8; + kThursday = 0x10; + kFriday = 0x20; + kSaturday = 0x40; + } + + struct ChargingTargetStruct { + int16u targetTimeMinutesPastMidnight = 0; + optional percent targetSoC = 1; + optional energy_mwh addedEnergy = 2; + } + + info event EVConnected = 0 { + int32u sessionID = 0; + } + + info event EVNotDetected = 1 { + int32u sessionID = 0; + StateEnum state = 1; + elapsed_s sessionDuration = 2; + energy_mwh sessionEnergyCharged = 3; + optional energy_mwh sessionEnergyDischarged = 4; + } + + info event EnergyTransferStarted = 2 { + int32u sessionID = 0; + StateEnum state = 1; + amperage_ma maximumCurrent = 2; + } + + info event EnergyTransferStopped = 3 { + int32u sessionID = 0; + StateEnum state = 1; + EnergyTransferStoppedReasonEnum reason = 2; + energy_mwh energyTransferred = 4; + } + + critical event Fault = 4 { + nullable int32u sessionID = 0; + StateEnum state = 1; + FaultStateEnum faultStatePreviousState = 2; + FaultStateEnum faultStateCurrentState = 4; + } + + info event RFID = 5 { + octet_string uid = 0; + } + + readonly attribute nullable StateEnum state = 0; + readonly attribute SupplyStateEnum supplyState = 1; + readonly attribute FaultStateEnum faultState = 2; + readonly attribute nullable epoch_s chargingEnabledUntil = 3; + readonly attribute optional nullable epoch_s dischargingEnabledUntil = 4; + readonly attribute amperage_ma circuitCapacity = 5; + readonly attribute amperage_ma minimumChargeCurrent = 6; + readonly attribute amperage_ma maximumChargeCurrent = 7; + readonly attribute optional amperage_ma maximumDischargeCurrent = 8; + attribute access(write: manage) optional amperage_ma userMaximumChargeCurrent = 9; + attribute access(write: manage) optional elapsed_s randomizationDelayWindow = 10; + readonly attribute optional int8u numberOfWeeklyTargets = 33; + readonly attribute optional int8u numberOfDailyTargets = 34; + readonly attribute optional nullable epoch_s nextChargeStartTime = 35; + readonly attribute optional nullable epoch_s nextChargeTargetTime = 36; + readonly attribute optional nullable energy_mwh nextChargeRequiredEnergy = 37; + readonly attribute optional nullable percent nextChargeTargetSoC = 38; + attribute access(write: manage) optional nullable int16u approximateEVEfficiency = 39; + readonly attribute optional nullable percent stateOfCharge = 48; + readonly attribute optional nullable energy_mwh batteryCapacity = 49; + readonly attribute optional nullable char_string<32> vehicleID = 50; + readonly attribute nullable int32u sessionID = 64; + readonly attribute nullable elapsed_s sessionDuration = 65; + readonly attribute nullable energy_mwh sessionEnergyCharged = 66; + readonly attribute optional nullable energy_mwh sessionEnergyDischarged = 67; + 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; + + response struct GetTargetsResponse = 0 { + TargetDayOfWeekBitmap dayOfWeekforSequence = 0; + ChargingTargetStruct chargingTargets[] = 1; + } + + request struct EnableChargingRequest { + nullable epoch_s chargingEnabledUntil = 0; + amperage_ma minimumChargeCurrent = 1; + amperage_ma maximumChargeCurrent = 2; + } + + request struct EnableDischargingRequest { + nullable epoch_s dischargingEnabledUntil = 0; + amperage_ma maximumDischargeCurrent = 1; + } + + request struct SetTargetsRequest { + TargetDayOfWeekBitmap dayOfWeekforSequence = 0; + ChargingTargetStruct chargingTargets[] = 1; + } + + request struct GetTargetsRequest { + TargetDayOfWeekBitmap daysToReturn = 0; + } + + /** Allows a client to disable the EVSE from charging and discharging. */ + timed command Disable(): DefaultSuccess = 1; + /** Allows a client to enable the EVSE to charge an EV. */ + timed command EnableCharging(EnableChargingRequest): DefaultSuccess = 2; + /** Allows a client to enable the EVSE to discharge an EV. */ + timed command EnableDischarging(EnableDischargingRequest): DefaultSuccess = 3; + /** Allows a client to put the EVSE into a self-diagnostics mode. */ + timed command StartDiagnostics(): DefaultSuccess = 4; + /** Allows a client to set the user specified charging targets. */ + timed command SetTargets(SetTargetsRequest): DefaultSuccess = 5; + /** Allows a client to retrieve the user specified charging targets. */ + timed command GetTargets(GetTargetsRequest): GetTargetsResponse = 6; + /** Allows a client to clear all stored charging targets. */ + timed command ClearTargets(): DefaultSuccess = 7; +} + +endpoint 0 { + device type ma_rootdevice = 22, version 1; + + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + callback attribute clusterRevision; + } + + server cluster AccessControl { + callback attribute acl; + callback attribute extension; + callback attribute subjectsPerAccessControlEntry; + callback attribute targetsPerAccessControlEntry; + callback attribute accessControlEntriesPerFabric; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + callback attribute clusterRevision; + } + + server cluster BasicInformation { + callback attribute dataModelRevision; + callback attribute vendorName; + callback attribute vendorID; + callback attribute productName; + callback attribute productID; + ram attribute nodeLabel; + callback attribute location; + callback attribute hardwareVersion; + callback attribute hardwareVersionString; + callback attribute softwareVersion; + callback attribute softwareVersionString; + callback attribute capabilityMinima; + callback attribute specificationVersion; + callback attribute maxPathsPerInvoke; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 3; + } + + server cluster UnitLocalization { + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster GeneralCommissioning { + ram attribute breadcrumb default = 0x0000000000000000; + callback attribute basicCommissioningInfo; + callback attribute regulatoryConfig; + callback attribute locationCapability; + callback attribute supportsConcurrentConnection; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command ArmFailSafe; + handle command ArmFailSafeResponse; + handle command SetRegulatoryConfig; + handle command SetRegulatoryConfigResponse; + handle command CommissioningComplete; + handle command CommissioningCompleteResponse; + } + + server cluster NetworkCommissioning { + ram attribute maxNetworks; + callback attribute networks; + ram attribute interfaceEnabled; + ram attribute lastNetworkingStatus; + ram attribute lastNetworkID; + ram attribute lastConnectErrorValue; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster GeneralDiagnostics { + callback attribute networkInterfaces; + callback attribute rebootCount; + ram attribute testEventTriggersEnabled; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command TestEventTrigger; + handle command TimeSnapshot; + handle command TimeSnapshotResponse; + } + + server cluster AdministratorCommissioning { + callback attribute windowStatus; + callback attribute adminFabricIndex; + callback attribute adminVendorId; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command OpenCommissioningWindow; + handle command RevokeCommissioning; + } + + server cluster OperationalCredentials { + callback attribute NOCs; + callback attribute fabrics; + callback attribute supportedFabrics; + callback attribute commissionedFabrics; + callback attribute trustedRootCertificates; + callback attribute currentFabricIndex; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command AttestationRequest; + handle command AttestationResponse; + handle command CertificateChainRequest; + handle command CertificateChainResponse; + handle command CSRRequest; + handle command CSRResponse; + handle command AddNOC; + handle command UpdateNOC; + handle command NOCResponse; + handle command UpdateFabricLabel; + handle command RemoveFabric; + handle command AddTrustedRootCertificate; + } + + server cluster GroupKeyManagement { + callback attribute groupKeyMap; + callback attribute groupTable; + callback attribute maxGroupsPerFabric; + callback attribute maxGroupKeysPerFabric; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command KeySetWrite; + handle command KeySetRead; + handle command KeySetReadResponse; + handle command KeySetRemove; + handle command KeySetReadAllIndices; + handle command KeySetReadAllIndicesResponse; + } +} +endpoint 1 { + device type ma_lightsensor = 262, version 1; + + + server cluster Identify { + ram attribute identifyTime default = 0x0; + ram attribute identifyType default = 0x00; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command Identify; + handle command TriggerEffect; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + callback attribute clusterRevision; + } + + server cluster EnergyEvse { + emits event EVConnected; + emits event EVNotDetected; + emits event EnergyTransferStarted; + emits event EnergyTransferStopped; + emits event Fault; + emits event RFID; + callback attribute state; + callback attribute supplyState; + callback attribute faultState; + callback attribute chargingEnabledUntil default = 0; + callback attribute dischargingEnabledUntil default = 0; + callback attribute circuitCapacity default = 0; + callback attribute minimumChargeCurrent default = 6000; + callback attribute maximumChargeCurrent default = 0; + callback attribute maximumDischargeCurrent default = 0; + callback attribute userMaximumChargeCurrent default = 0; + callback attribute randomizationDelayWindow default = 600; + callback attribute numberOfWeeklyTargets default = 0; + callback attribute numberOfDailyTargets default = 1; + callback attribute nextChargeStartTime; + callback attribute nextChargeTargetTime; + callback attribute nextChargeRequiredEnergy; + callback attribute nextChargeTargetSoC; + callback attribute approximateEVEfficiency default = 0xFFFF; + callback attribute stateOfCharge; + callback attribute batteryCapacity; + callback attribute vehicleID; + callback attribute sessionID default = 0; + callback attribute sessionDuration default = 0; + callback attribute sessionEnergyCharged default = 0; + callback attribute sessionEnergyDischarged default = 0; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 1; + ram attribute clusterRevision default = 2; + + handle command GetTargetsResponse; + handle command Disable; + handle command EnableCharging; + handle command EnableDischarging; + handle command StartDiagnostics; + handle command SetTargets; + handle command GetTargets; + handle command ClearTargets; + } +} + + diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.zap b/examples/energy-management-app/energy-management-common/energy-management-app.zap new file mode 100644 index 00000000000000..55d62101227dab --- /dev/null +++ b/examples/energy-management-app/energy-management-common/energy-management-app.zap @@ -0,0 +1,3157 @@ +{ + "fileFormat": 2, + "featureLevel": 99, + "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": [ + { + "id": 1, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice" + }, + "deviceTypes": [ + { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice" + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 22 + ], + "deviceTypeName": "MA-rootdevice", + "deviceTypeCode": 22, + "deviceTypeProfileId": 259, + "clusters": [ + { + "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": null, + "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": null, + "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": null, + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 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": null, + "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": null, + "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": null, + "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": null, + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "VendorName", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "VendorID", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ProductName", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ProductID", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NodeLabel", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Location", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HardwareVersion", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HardwareVersionString", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SoftwareVersion", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SoftwareVersionString", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CapabilityMinima", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "CapabilityMinimaStruct", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SpecificationVersion", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxPathsPerInvoke", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "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": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Unit Localization", + "code": 45, + "mfgCode": null, + "define": "UNIT_LOCALIZATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Commissioning", + "code": 48, + "mfgCode": null, + "define": "GENERAL_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ArmFailSafe", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ArmFailSafeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfig", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfigResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CommissioningComplete", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CommissioningCompleteResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 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": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BasicCommissioningInfo", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "BasicCommissioningInfo", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RegulatoryConfig", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "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": null, + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Network Commissioning", + "code": 49, + "mfgCode": null, + "define": "NETWORK_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 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": null, + "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": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Diagnostics", + "code": 51, + "mfgCode": null, + "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "TestEventTrigger", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshot", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshotResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NetworkInterfaces", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RebootCount", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TestEventTriggersEnabled", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "boolean", + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Administrator Commissioning", + "code": 60, + "mfgCode": null, + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "OpenCommissioningWindow", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RevokeCommissioning", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "WindowStatus", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "CommissioningWindowStatusEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminVendorId", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Operational Credentials", + "code": 62, + "mfgCode": null, + "define": "OPERATIONAL_CREDENTIALS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AttestationRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AttestationResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CertificateChainRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CertificateChainResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CSRRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CSRResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddNOC", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "UpdateNOC", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NOCResponse", + "code": 8, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "UpdateFabricLabel", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveFabric", + "code": 10, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddTrustedRootCertificate", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NOCs", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Fabrics", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedFabrics", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CommissionedFabrics", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TrustedRootCertificates", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentFabricIndex", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Group Key Management", + "code": 63, + "mfgCode": null, + "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "KeySetWrite", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetRead", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "KeySetRemove", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndices", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndicesResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "GroupKeyMap", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GroupTable", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupsPerFabric", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 2, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 262, + "profileId": 259, + "label": "MA-lightsensor", + "name": "MA-lightsensor" + }, + "deviceTypes": [ + { + "code": 262, + "profileId": 259, + "label": "MA-lightsensor", + "name": "MA-lightsensor" + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 262 + ], + "deviceTypeName": "MA-lightsensor", + "deviceTypeCode": 262, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 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": "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "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": null, + "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": null, + "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": null, + "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": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Energy EVSE", + "code": 153, + "mfgCode": null, + "define": "ENERGY_EVSE_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "GetTargetsResponse", + "code": 0, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "Disable", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "EnableCharging", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "EnableDischarging", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StartDiagnostics", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetTargets", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "GetTargets", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ClearTargets", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "State", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "StateEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupplyState", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "SupplyStateEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FaultState", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "FaultStateEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ChargingEnabledUntil", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "epoch_s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "DischargingEnabledUntil", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "epoch_s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CircuitCapacity", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinimumChargeCurrent", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "6000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaximumChargeCurrent", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaximumDischargeCurrent", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UserMaximumChargeCurrent", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RandomizationDelayWindow", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "elapsed_s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "600", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfWeeklyTargets", + "code": 33, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfDailyTargets", + "code": 34, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NextChargeStartTime", + "code": 35, + "mfgCode": null, + "side": "server", + "type": "epoch_s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NextChargeTargetTime", + "code": 36, + "mfgCode": null, + "side": "server", + "type": "epoch_s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NextChargeRequiredEnergy", + "code": 37, + "mfgCode": null, + "side": "server", + "type": "energy_mwh", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NextChargeTargetSoC", + "code": 38, + "mfgCode": null, + "side": "server", + "type": "percent", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ApproximateEVEfficiency", + "code": 39, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFFFF", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "StateOfCharge", + "code": 48, + "mfgCode": null, + "side": "server", + "type": "percent", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BatteryCapacity", + "code": 49, + "mfgCode": null, + "side": "server", + "type": "energy_mwh", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "VehicleID", + "code": 50, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SessionID", + "code": 64, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SessionDuration", + "code": 65, + "mfgCode": null, + "side": "server", + "type": "elapsed_s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SessionEnergyCharged", + "code": 66, + "mfgCode": null, + "side": "server", + "type": "energy_mwh", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SessionEnergyDischarged", + "code": 67, + "mfgCode": null, + "side": "server", + "type": "energy_mwh", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "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": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "EVConnected", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "EVNotDetected", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "EnergyTransferStarted", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "EnergyTransferStopped", + "code": 3, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "Fault", + "code": 4, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "RFID", + "code": 5, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + } + ] + } + ], + "endpoints": [ + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 0, + "profileId": 259, + "endpointId": 0, + "networkId": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 1, + "profileId": 259, + "endpointId": 1, + "networkId": 0 + } + ], + "log": [] +} \ No newline at end of file diff --git a/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h b/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h new file mode 100644 index 00000000000000..34e9027e626ad5 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.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. + */ + +#pragma once + +#include + +using chip::Protocols::InteractionModel::Status; +namespace chip { +namespace app { +namespace Clusters { +namespace EnergyEvse { + +/** + * The EVSEManufacturer example class + */ + +class EVSEManufacturer +{ +public: + /** + * @brief Called at start up to apply hardware settings + */ + CHIP_ERROR Init(EnergyEvseManager * aInstance); + + /** + * @brief Called at shutdown + */ + CHIP_ERROR Shutdown(EnergyEvseManager * aInstance); + +private: +}; + +} // namespace EnergyEvse +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h b/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h new file mode 100644 index 00000000000000..0a967e2472be8b --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/EnergyEvseDelegateImpl.h @@ -0,0 +1,196 @@ +/* + * + * 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 "app/clusters/energy-evse-server/energy-evse-server.h" + +#include +#include +#include + +using chip::Protocols::InteractionModel::Status; +namespace chip { +namespace app { +namespace Clusters { +namespace EnergyEvse { + +/** + * The application delegate. + */ + +class EnergyEvseDelegate : public EnergyEvse::Delegate +{ +public: + ~EnergyEvseDelegate(); + + /** + * @brief Called when EVSE cluster receives Disable command + */ + Status Disable() override; + + /** + * @brief Called when EVSE cluster receives EnableCharging command + * + * @param chargingEnabledUntil + * @param minimumChargeCurrent (in mA) + * @param maximumChargeCurrent (in mA) + */ + Status EnableCharging(const DataModel::Nullable & chargingEnabledUntil, const int64_t & minimumChargeCurrent, + const int64_t & maximumChargeCurrent) override; + + /** + * @brief Called when EVSE cluster receives EnableDischarging command + * + * @param dischargingEnabledUntil + * @param maximumChargeCurrent (in mA) + */ + Status EnableDischarging(const DataModel::Nullable & dischargingEnabledUntil, + const int64_t & maximumDischargeCurrent) override; + + /** + * @brief Called when EVSE cluster receives StartDiagnostics command + */ + Status StartDiagnostics() override; + + // ----------------------------------------------------------------- + // Internal API to allow an EVSE to change its internal state etc + // TODO Status HwRegisterEvseHardwareCallback(Callback); + Status HwSetMaxHardwareCurrentLimit(int64_t currentmA); + Status HwSetCircuitCapacity(int64_t currentmA); + Status HwSetCableAssemblyLimit(int64_t currentmA); + Status HwSetState(StateEnum state); + Status HwSetFault(FaultStateEnum fault); + Status HwSetRFID(ByteSpan uid); + Status HwSetVehicleID(const CharSpan & vehID); + + // ------------------------------------------------------------------ + // Get attribute methods + StateEnum GetState() override; + CHIP_ERROR SetState(StateEnum); + + SupplyStateEnum GetSupplyState() override; + CHIP_ERROR SetSupplyState(SupplyStateEnum); + + FaultStateEnum GetFaultState() override; + CHIP_ERROR SetFaultState(FaultStateEnum); + + DataModel::Nullable GetChargingEnabledUntil() override; + CHIP_ERROR SetChargingEnabledUntil(uint32_t); + + DataModel::Nullable GetDischargingEnabledUntil() override; + CHIP_ERROR SetDischargingEnabledUntil(uint32_t); + + int64_t GetCircuitCapacity() override; + CHIP_ERROR SetCircuitCapacity(int64_t); + + int64_t GetMinimumChargeCurrent() override; + CHIP_ERROR SetMinimumChargeCurrent(int64_t); + + int64_t GetMaximumChargeCurrent() override; + CHIP_ERROR SetMaximumChargeCurrent(int64_t); + + int64_t GetMaximumDischargeCurrent() override; + CHIP_ERROR SetMaximumDischargeCurrent(int64_t); + + int64_t GetUserMaximumChargeCurrent() override; + CHIP_ERROR SetUserMaximumChargeCurrent(int64_t) override; + + uint32_t GetRandomizationDelayWindow() override; + CHIP_ERROR SetRandomizationDelayWindow(uint32_t) override; + + /* PREF attributes */ + uint8_t GetNumberOfWeeklyTargets() override; + uint8_t GetNumberOfDailyTargets() override; + DataModel::Nullable GetNextChargeStartTime() override; + DataModel::Nullable GetNextChargeTargetTime() override; + DataModel::Nullable GetNextChargeRequiredEnergy() override; + DataModel::Nullable GetNextChargeTargetSoC() override; + + DataModel::Nullable GetApproximateEVEfficiency() override; + CHIP_ERROR SetApproximateEVEfficiency(uint16_t) override; + + /* SOC attributes */ + DataModel::Nullable GetStateOfCharge() override; + DataModel::Nullable GetBatteryCapacity() override; + /* PNC attributes*/ + DataModel::Nullable GetVehicleID() override; + /* Session SESS attributes */ + DataModel::Nullable GetSessionID() override; + DataModel::Nullable GetSessionDuration() override; + DataModel::Nullable GetSessionEnergyCharged() override; + DataModel::Nullable GetSessionEnergyDischarged() override; + +private: + /* Constants */ + static constexpr int DEFAULT_MIN_CHARGE_CURRENT = 6000; /* 6A */ + static constexpr int DEFAULT_USER_MAXIMUM_CHARGE_CURRENT = kMaximumChargeCurrent; /* 80A */ + static constexpr int DEFAULT_RANDOMIZATION_DELAY_WINDOW = 600; /* 600s */ + static constexpr int kMaxVehicleIDBufSize = 32; + + /* private variables for controlling the hardware - these are not attributes */ + int64_t mMaxHardwareCurrentLimit = 0; /* Hardware current limit in mA */ + int64_t mCableAssemblyCurrentLimit = 0; /* Cable limit detected when cable is plugged in, in mA */ + int64_t mMaximumChargingCurrentLimitFromCommand = 0; /* Value of current maximum limit when charging enabled */ + int64_t mActualChargingCurrentLimit = 0; + StateEnum mHwState = StateEnum::kNotPluggedIn; /* Hardware state */ + + /** + * @brief Helper function to work out the charge limit based on conditions and settings + */ + Status ComputeMaxChargeCurrentLimit(); + + /* Attributes */ + StateEnum mState = StateEnum::kNotPluggedIn; + SupplyStateEnum mSupplyState = SupplyStateEnum::kDisabled; + FaultStateEnum mFaultState = FaultStateEnum::kNoError; + DataModel::Nullable mChargingEnabledUntil; // TODO Default to 0 to indicate disabled + DataModel::Nullable mDischargingEnabledUntil; // TODO Default to 0 to indicate disabled + int64_t mCircuitCapacity = 0; + int64_t mMinimumChargeCurrent = DEFAULT_MIN_CHARGE_CURRENT; + int64_t mMaximumChargeCurrent = 0; + int64_t mMaximumDischargeCurrent = 0; + int64_t mUserMaximumChargeCurrent = DEFAULT_USER_MAXIMUM_CHARGE_CURRENT; // TODO update spec + uint32_t mRandomizationDelayWindow = DEFAULT_RANDOMIZATION_DELAY_WINDOW; + /* PREF attributes */ + uint8_t mNumberOfWeeklyTargets = 0; + uint8_t mNumberOfDailyTargets = 1; + DataModel::Nullable mNextChargeStartTime; + DataModel::Nullable mNextChargeTargetTime; + DataModel::Nullable mNextChargeRequiredEnergy; + DataModel::Nullable mNextChargeTargetSoC; + DataModel::Nullable mApproximateEVEfficiency; + + /* SOC attributes */ + DataModel::Nullable mStateOfCharge; + DataModel::Nullable mBatteryCapacity; + + /* PNC attributes*/ + DataModel::Nullable mVehicleID; + + /* Session SESS attributes */ + DataModel::Nullable mSessionID; + DataModel::Nullable mSessionDuration; + DataModel::Nullable mSessionEnergyCharged; + DataModel::Nullable mSessionEnergyDischarged; +}; + +} // namespace EnergyEvse +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h b/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h new file mode 100644 index 00000000000000..9875c397990ef2 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/EnergyEvseManager.h @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { + +using namespace chip::app::Clusters::EnergyEvse; +class EnergyEvseManager : public Instance +{ +public: + EnergyEvseManager(EndpointId aEndpointId, EnergyEvseDelegate & aDelegate, Feature aFeature, OptionalAttributes aOptionalAttrs, + OptionalCommands aOptionalCmds) : + EnergyEvse::Instance(aEndpointId, aDelegate, aFeature, aOptionalAttrs, aOptionalCmds) + { + mDelegate = &aDelegate; + } + + // Delete copy constructor and assignment operator. + EnergyEvseManager(const EnergyEvseManager &) = delete; + EnergyEvseManager(const EnergyEvseManager &&) = delete; + EnergyEvseManager & operator=(const EnergyEvseManager &) = delete; + + CHIP_ERROR Init(); + void Shutdown(); + + EnergyEvseDelegate * GetDelegate() { return mDelegate; }; + +private: + EnergyEvseDelegate * mDelegate; +}; + +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/include/EnergyManagementManager.h b/examples/energy-management-app/energy-management-common/include/EnergyManagementManager.h new file mode 100644 index 00000000000000..3dac6f579c609e --- /dev/null +++ b/examples/energy-management-app/energy-management-common/include/EnergyManagementManager.h @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include diff --git a/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp new file mode 100644 index 00000000000000..e5ad19306ea239 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::EnergyEvse; + +CHIP_ERROR EVSEManufacturer::Init(EnergyEvseManager * aInstance) +{ + /* Manufacturers should modify this to do any custom initialisation */ + + /* Register callbacks */ + EnergyEvseDelegate * dg = aInstance->GetDelegate(); + if (dg == nullptr) + { + ChipLogError(AppServer, "Delegate is not initialized"); + return CHIP_ERROR_UNINITIALIZED; + } + + // TODO EnergyEvseManager::GetInstance()->GetDelegate()->RegisterCallbacks(); + + /* Set the EVSE Hardware Maximum current limit */ + // For Manufacturer to specify the hardware capability in mA + dg->HwSetMaxHardwareCurrentLimit(32000); + + // For Manufacturer to specify the CircuitCapacity (e.g. from DIP switches) + dg->HwSetCircuitCapacity(20000); + + /* For now let's pretend the EV is plugged in, and asking for demand */ + dg->HwSetState(StateEnum::kPluggedInDemand); + dg->HwSetCableAssemblyLimit(63000); + + /* For now let's pretend the vehicle ID is set */ + dg->HwSetVehicleID(CharSpan::fromCharString("TEST_VEHICLE_123456789")); + dg->HwSetVehicleID(CharSpan::fromCharString("TEST_VEHICLE_9876543210")); + + /* This next one will fail because it is too long */ + dg->HwSetVehicleID(CharSpan::fromCharString("TEST_VEHICLE_9876543210TOOOOOOOOOOOOOOOOOOO")); + + /* For now let's pretend the RFID sensor was triggered - send an event */ + uint8_t uid[10] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE }; + dg->HwSetRFID(ByteSpan(uid)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR EVSEManufacturer::Shutdown(EnergyEvseManager * aInstance) +{ + + return CHIP_NO_ERROR; +} diff --git a/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp new file mode 100644 index 00000000000000..7ad16c3737dacb --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp @@ -0,0 +1,793 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::DataModel; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::EnergyEvse; +using namespace chip::app::Clusters::EnergyEvse::Attributes; + +using chip::app::LogEvent; +using chip::Protocols::InteractionModel::Status; + +EnergyEvseDelegate::~EnergyEvseDelegate() +{ + // TODO Fix this as part of issue #30993 refactoring + if (!mVehicleID.IsNull()) + { + ChipLogDetail(AppServer, "Freeing VehicleID"); + delete[] mVehicleID.Value().data(); + } +} + +/** + * @brief Called when EVSE cluster receives Disable command + */ +Status EnergyEvseDelegate::Disable() +{ + ChipLogProgress(AppServer, "EnergyEvseDelegate::Disable()"); + + /* update State */ + switch (mHwState) + { + case StateEnum::kNotPluggedIn: + SetState(StateEnum::kNotPluggedIn); + break; + + case StateEnum::kPluggedInNoDemand: + SetState(StateEnum::kPluggedInNoDemand); + break; + + case StateEnum::kPluggedInDemand: + SetState(StateEnum::kPluggedInDemand); + break; + + default: + ChipLogError(AppServer, "Unexpected EVSE hardware state"); + SetState(StateEnum::kFault); + break; + } + + /* update SupplyState */ + SetSupplyState(SupplyStateEnum::kDisabled); + + /* update ChargingEnabledUntil & DischargingEnabledUntil to show 0 */ + SetChargingEnabledUntil(0); + SetDischargingEnabledUntil(0); + + /* update MinimumChargeCurrent & MaximumChargeCurrent to 0 */ + SetMinimumChargeCurrent(0); + SetMaximumChargeCurrent(0); + + /* update MaximumDischargeCurrent to 0 */ + SetMaximumDischargeCurrent(0); + + // TODO: Generate events + + return Status::Success; +} + +/** + * @brief Called when EVSE cluster receives EnableCharging command + * + * @param chargingEnabledUntil (can be null to indefinite charging) + * @param minimumChargeCurrent (in mA) + * @param maximumChargeCurrent (in mA) + */ +Status EnergyEvseDelegate::EnableCharging(const DataModel::Nullable & chargingEnabledUntil, + const int64_t & minimumChargeCurrent, const int64_t & maximumChargeCurrent) +{ + ChipLogProgress(AppServer, "EnergyEvseDelegate::EnableCharging()"); + + if (maximumChargeCurrent < kMinimumChargeCurrent || maximumChargeCurrent > kMaximumChargeCurrent) + { + ChipLogError(NotSpecified, "Maximum Current outside limits"); + return Status::ConstraintError; + } + + if (minimumChargeCurrent < kMinimumChargeCurrent || minimumChargeCurrent > kMaximumChargeCurrent) + { + ChipLogError(NotSpecified, "Maximum Current outside limits"); + return Status::ConstraintError; + } + + if (minimumChargeCurrent > maximumChargeCurrent) + { + ChipLogError(NotSpecified, "Minium Current > Maximum Current!"); + return Status::ConstraintError; + } + + if (chargingEnabledUntil.IsNull()) + { + /* Charging enabled indefinitely */ + ChipLogError(NotSpecified, "Charging enabled indefinitely"); + } + else + { + /* check chargingEnabledUntil is in the future */ + ChipLogError(NotSpecified, "Charging enabled until: %lu", static_cast(chargingEnabledUntil.Value())); + // TODO + // if (checkChargingEnabled) + } + + /* Check current state isn't already enabled */ + + /* If charging is already enabled, check that the parameters may have + changed, these may override an existing charging command */ + switch (mHwState) + { + case StateEnum::kNotPluggedIn: + // TODO handle errors here + SetState(StateEnum::kNotPluggedIn); + break; + + case StateEnum::kPluggedInNoDemand: + // TODO handle errors here + // TODO REFACTOR per Andrei's comment in PR30857 - can we collapse this switch statement? + SetState(StateEnum::kPluggedInNoDemand); + break; + + case StateEnum::kPluggedInDemand: + /* If the EVSE is asking for demand then enable charging */ + SetState(StateEnum::kPluggedInCharging); + break; + + default: + ChipLogError(AppServer, "Unexpected EVSE hardware state"); + SetState(StateEnum::kFault); + break; + } + + /* update SupplyState to say that charging is now enabled */ + SetSupplyState(SupplyStateEnum::kChargingEnabled); + + /* If it looks ok, store the min & max charging current */ + mMaximumChargingCurrentLimitFromCommand = maximumChargeCurrent; + SetMinimumChargeCurrent(minimumChargeCurrent); + // TODO persist these to KVS + + // TODO: Generate events + + return this->ComputeMaxChargeCurrentLimit(); +} + +/** + * @brief Called when EVSE cluster receives EnableDischarging command + * + * @param dischargingEnabledUntil (can be null to indefinite discharging) + * @param maximumChargeCurrent (in mA) + */ +Status EnergyEvseDelegate::EnableDischarging(const DataModel::Nullable & dischargingEnabledUntil, + const int64_t & maximumDischargeCurrent) +{ + ChipLogProgress(AppServer, "EnergyEvseDelegate::EnableDischarging() called."); + + /* update SupplyState */ + SetSupplyState(SupplyStateEnum::kDischargingEnabled); + + // TODO: Generate events + + return Status::Success; +} + +/** + * @brief Called when EVSE cluster receives StartDiagnostics command + */ +Status EnergyEvseDelegate::StartDiagnostics() +{ + /* For EVSE manufacturers to customize */ + ChipLogProgress(AppServer, "EnergyEvseDelegate::StartDiagnostics()"); + + /* update SupplyState */ + SetSupplyState(SupplyStateEnum::kDisabledDiagnostics); + + // TODO: Generate events + + return Status::Success; +} + +/* --------------------------------------------------------------------------- + * FUNCTIONS BELOW: + * - EVSE Hardware interface + * + * SetMaxHardwareCurrentLimit( currentmA ) + * SetCircuitCapacity( currentmA ) + * SetCableAssemblyLimit( currentmA ) + * SetState( EVSEStateEnum ) + * SetFault + * + */ + +/** + * @brief Called by EVSE Hardware to notify the delegate of the maximum + * current limit supported by the hardware. + * + * This is normally called at start-up. + * + * @param currentmA - Maximum current limit supported by the hardware + */ +Status EnergyEvseDelegate::HwSetMaxHardwareCurrentLimit(int64_t currentmA) +{ + if (currentmA < kMinimumChargeCurrent || currentmA > kMaximumChargeCurrent) + { + return Status::ConstraintError; + } + + /* there is no attribute to store this so store in private variable */ + mMaxHardwareCurrentLimit = currentmA; + + return this->ComputeMaxChargeCurrentLimit(); +} + +/** + * @brief Called by EVSE Hardware to notify the delegate of maximum electrician + * set current limit. + * + * This is normally called at start-up when reading from DIP-switch + * settings. + * + * @param currentmA - Maximum current limit specified by electrician + */ +Status EnergyEvseDelegate::HwSetCircuitCapacity(int64_t currentmA) +{ + if (currentmA < kMinimumChargeCurrent || currentmA > kMaximumChargeCurrent) + { + return Status::ConstraintError; + } + + mCircuitCapacity = currentmA; + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, CircuitCapacity::Id); + + return this->ComputeMaxChargeCurrentLimit(); +} + +/** + * @brief Called by EVSE Hardware to notify the delegate of the cable assembly + * current limit. + * + * This is normally called when the EV is plugged into the EVSE and the + * PP voltage is measured by the EVSE. A pull-up resistor in the cable + * causes a voltage drop. Different current limits can be indicated + * using different resistors, which results in different voltages + * measured by the EVSE. + * + * @param currentmA - Maximum current limit detected from Cable assembly + */ +Status EnergyEvseDelegate::HwSetCableAssemblyLimit(int64_t currentmA) +{ + if (currentmA < kMinimumChargeCurrent || currentmA > kMaximumChargeCurrent) + { + return Status::ConstraintError; + } + + /* there is no attribute to store this so store in private variable */ + mCableAssemblyCurrentLimit = currentmA; + + return this->ComputeMaxChargeCurrentLimit(); +} + +/** + * @brief Called by EVSE Hardware to indicate if EV is detected + * + * The only allowed states that the EVSE hardware can set are: + * kNotPluggedIn + * kPluggedInNoDemand + * kPluggedInDemand + * + * @param StateEnum - the state of the EV being plugged in and asking for demand etc + */ +Status EnergyEvseDelegate::HwSetState(StateEnum state) +{ + switch (state) + { + case StateEnum::kNotPluggedIn: + // TODO - work out logic here + mHwState = state; + break; + case StateEnum::kPluggedInNoDemand: + // TODO - work out logic here + mHwState = state; + break; + case StateEnum::kPluggedInDemand: + // TODO - work out logic here + mHwState = state; + break; + + default: + /* All other states should be managed by the Delegate */ + // TODO (assert?) + break; + } + + return Status::Success; +} + +/** + * @brief Called by EVSE Hardware to indicate a fault + * + * @param FaultStateEnum - the fault condition detected + */ +Status EnergyEvseDelegate::HwSetFault(FaultStateEnum fault) +{ + ChipLogProgress(AppServer, "EnergyEvseDelegate::Fault()"); + + if (fault == FaultStateEnum::kNoError) + { + /* Update State to previous state */ + // TODO: need to work out the logic here! + + /* Update SupplyState to previous state */ + } + else + { + /* Update State & SupplyState */ + SetState(StateEnum::kFault); + SetSupplyState(SupplyStateEnum::kDisabledError); + } + + /* Update FaultState */ + SetFaultState(fault); + + // TODO: Generate events + + return Status::Success; +} + +/** + * @brief Called by EVSE Hardware to Send a RFID event + * + * @param ByteSpan RFID tag value (max 10 octets) + */ +Status EnergyEvseDelegate::HwSetRFID(ByteSpan uid) +{ + Events::Rfid::Type event{ .uid = uid }; + EventNumber eventNumber; + CHIP_ERROR error = LogEvent(event, mEndpointId, eventNumber); + if (CHIP_NO_ERROR != error) + { + ChipLogError(Zcl, "[Notify] Unable to send notify event: %s [endpointId=%d]", error.AsString(), mEndpointId); + return Status::Failure; + } + + return Status::Success; +} + +/** + * @brief Called by EVSE Hardware to share the VehicleID + * + * This routine will make a copy of the string so the callee doesn't + * have to hold onto it forever. + * + * @param CharSpan containing up to 32 chars. + */ +Status EnergyEvseDelegate::HwSetVehicleID(const CharSpan & newValue) +{ + // TODO this code to be refactored - See Issue #30993 + if (!mVehicleID.IsNull() && newValue.data_equal(mVehicleID.Value())) + { + return Status::Success; + } + + /* create a copy of the string so the callee doesn't have to keep it */ + char * destinationBuffer = new char[kMaxVehicleIDBufSize]; + + MutableCharSpan destinationString(destinationBuffer, kMaxVehicleIDBufSize); + CHIP_ERROR err = CopyCharSpanToMutableCharSpan(newValue, destinationString); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "HwSetVehicleID - could not copy vehicleID"); + delete[] destinationBuffer; + return Status::Failure; + } + + if (!mVehicleID.IsNull()) + { + delete[] mVehicleID.Value().data(); + } + + mVehicleID = MakeNullable(static_cast(destinationString)); + + ChipLogDetail(AppServer, "VehicleID updated %.*s", static_cast(mVehicleID.Value().size()), mVehicleID.Value().data()); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, VehicleID::Id); + + return Status::Success; +} + +/* --------------------------------------------------------------------------- + * Functions below are private helper functions internal to the delegate + */ + +/** + * @brief Called to compute the safe charging current limit + */ +Status EnergyEvseDelegate::ComputeMaxChargeCurrentLimit() +{ + int64_t oldValue; + /* mActualChargingCurrentLimit is the minimum of: + * - MaxHardwareCurrentLimit (of the hardware) + * - CircuitCapacity (set by the electrician - less than the hardware) + * - CableAssemblyLimit (detected when the cable is inserted) + * - MaximumChargeCurrent (from charging command) + * - UserMaximumChargeCurrent (could dynamically change) + */ + + oldValue = mActualChargingCurrentLimit; + mActualChargingCurrentLimit = mMaxHardwareCurrentLimit; + mActualChargingCurrentLimit = min(mActualChargingCurrentLimit, mCircuitCapacity); + mActualChargingCurrentLimit = min(mActualChargingCurrentLimit, mCableAssemblyCurrentLimit); + mActualChargingCurrentLimit = min(mActualChargingCurrentLimit, mMaximumChargingCurrentLimitFromCommand); + mActualChargingCurrentLimit = min(mActualChargingCurrentLimit, mUserMaximumChargeCurrent); + + /* Set the actual max charging current attribute */ + mMaximumChargeCurrent = mActualChargingCurrentLimit; + + if (oldValue != mMaximumChargeCurrent) + { + ChipLogDetail(AppServer, "MaximumChargeCurrent updated to %ld", static_cast(mMaximumChargeCurrent)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, MaximumChargeCurrent::Id); + + /* Call the EV Charger hardware current limit callback */ + // TODO + } + return Status::Success; +} + +/** + * Attribute methods + */ +/* State */ +StateEnum EnergyEvseDelegate::GetState() +{ + return mState; +} + +CHIP_ERROR EnergyEvseDelegate::SetState(StateEnum newValue) +{ + StateEnum oldValue = mState; + if (newValue >= StateEnum::kUnknownEnumValue) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mState = newValue; + if (oldValue != mState) + { + ChipLogDetail(AppServer, "State updated to %d", static_cast(mState)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, State::Id); + } + + return CHIP_NO_ERROR; +} + +/* SupplyState */ +SupplyStateEnum EnergyEvseDelegate::GetSupplyState() +{ + return mSupplyState; +} + +CHIP_ERROR EnergyEvseDelegate::SetSupplyState(SupplyStateEnum newValue) +{ + SupplyStateEnum oldValue = mSupplyState; + + if (newValue >= SupplyStateEnum::kUnknownEnumValue) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mSupplyState = newValue; + if (oldValue != mSupplyState) + { + ChipLogDetail(AppServer, "SupplyState updated to %d", static_cast(mSupplyState)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, SupplyState::Id); + } + return CHIP_NO_ERROR; +} + +/* FaultState */ +FaultStateEnum EnergyEvseDelegate::GetFaultState() +{ + return mFaultState; +} + +CHIP_ERROR EnergyEvseDelegate::SetFaultState(FaultStateEnum newValue) +{ + FaultStateEnum oldValue = mFaultState; + + if (newValue >= FaultStateEnum::kUnknownEnumValue) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mFaultState = newValue; + if (oldValue != mFaultState) + { + ChipLogDetail(AppServer, "FaultState updated to %d", static_cast(mFaultState)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, FaultState::Id); + } + return CHIP_NO_ERROR; +} + +/* ChargingEnabledUntil */ +DataModel::Nullable EnergyEvseDelegate::GetChargingEnabledUntil() +{ + return mChargingEnabledUntil; +} + +CHIP_ERROR EnergyEvseDelegate::SetChargingEnabledUntil(uint32_t newValue) +{ + DataModel::Nullable oldValue = mChargingEnabledUntil; + + mChargingEnabledUntil = MakeNullable(newValue); + if ((oldValue.IsNull()) || (oldValue.Value() != newValue)) + { + ChipLogDetail(AppServer, "ChargingEnabledUntil updated to %lu", + static_cast(mChargingEnabledUntil.Value())); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, ChargingEnabledUntil::Id); + } + return CHIP_NO_ERROR; +} + +/* DischargingEnabledUntil */ +DataModel::Nullable EnergyEvseDelegate::GetDischargingEnabledUntil() +{ + return mDischargingEnabledUntil; +} + +CHIP_ERROR EnergyEvseDelegate::SetDischargingEnabledUntil(uint32_t newValue) +{ + DataModel::Nullable oldValue = mDischargingEnabledUntil; + + mDischargingEnabledUntil = MakeNullable(newValue); + if ((oldValue.IsNull()) || (oldValue.Value() != newValue)) + { + ChipLogDetail(AppServer, "DischargingEnabledUntil updated to %lu", + static_cast(mDischargingEnabledUntil.Value())); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, DischargingEnabledUntil::Id); + } + return CHIP_NO_ERROR; +} + +/* CircuitCapacity */ +int64_t EnergyEvseDelegate::GetCircuitCapacity() +{ + return mCircuitCapacity; +} + +CHIP_ERROR EnergyEvseDelegate::SetCircuitCapacity(int64_t newValue) +{ + int64_t oldValue = mCircuitCapacity; + + if (newValue >= kMaximumChargeCurrent) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mCircuitCapacity = newValue; + if (oldValue != mCircuitCapacity) + { + ChipLogDetail(AppServer, "CircuitCapacity updated to %ld", static_cast(mCircuitCapacity)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, CircuitCapacity::Id); + } + return CHIP_NO_ERROR; +} + +/* MinimumChargeCurrent */ +int64_t EnergyEvseDelegate::GetMinimumChargeCurrent() +{ + return mMinimumChargeCurrent; +} + +CHIP_ERROR EnergyEvseDelegate::SetMinimumChargeCurrent(int64_t newValue) +{ + int64_t oldValue = mMinimumChargeCurrent; + + if (newValue >= kMaximumChargeCurrent) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mMinimumChargeCurrent = newValue; + if (oldValue != mMinimumChargeCurrent) + { + ChipLogDetail(AppServer, "MinimumChargeCurrent updated to %ld", static_cast(mMinimumChargeCurrent)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, MinimumChargeCurrent::Id); + } + return CHIP_NO_ERROR; +} + +/* MaximumChargeCurrent */ +int64_t EnergyEvseDelegate::GetMaximumChargeCurrent() +{ + return mMaximumChargeCurrent; +} + +CHIP_ERROR EnergyEvseDelegate::SetMaximumChargeCurrent(int64_t newValue) +{ + int64_t oldValue = mMaximumChargeCurrent; + + if (newValue >= kMaximumChargeCurrent) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mMaximumChargeCurrent = newValue; + if (oldValue != mMaximumChargeCurrent) + { + ChipLogDetail(AppServer, "MaximumChargeCurrent updated to %ld", static_cast(mMaximumChargeCurrent)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, MaximumChargeCurrent::Id); + } + return CHIP_NO_ERROR; +} + +/* MaximumDischargeCurrent */ +int64_t EnergyEvseDelegate::GetMaximumDischargeCurrent() +{ + return mMaximumDischargeCurrent; +} + +CHIP_ERROR EnergyEvseDelegate::SetMaximumDischargeCurrent(int64_t newValue) +{ + int64_t oldValue = mMaximumDischargeCurrent; + + if (newValue >= kMaximumChargeCurrent) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mMaximumDischargeCurrent = newValue; + if (oldValue != mMaximumDischargeCurrent) + { + ChipLogDetail(AppServer, "MaximumDischargeCurrent updated to %ld", static_cast(mMaximumDischargeCurrent)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, MaximumDischargeCurrent::Id); + } + return CHIP_NO_ERROR; +} + +/* UserMaximumChargeCurrent */ +int64_t EnergyEvseDelegate::GetUserMaximumChargeCurrent() +{ + return mUserMaximumChargeCurrent; +} + +CHIP_ERROR EnergyEvseDelegate::SetUserMaximumChargeCurrent(int64_t newValue) +{ + if ((newValue < 0) || (newValue > kMaximumChargeCurrent)) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + int64_t oldValue = mUserMaximumChargeCurrent; + mUserMaximumChargeCurrent = newValue; + if (oldValue != newValue) + { + ChipLogDetail(AppServer, "UserMaximumChargeCurrent updated to %ld", static_cast(mUserMaximumChargeCurrent)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, UserMaximumChargeCurrent::Id); + } + + return CHIP_NO_ERROR; +} + +/* RandomizationDelayWindow */ +uint32_t EnergyEvseDelegate::GetRandomizationDelayWindow() +{ + return mRandomizationDelayWindow; +} + +CHIP_ERROR EnergyEvseDelegate::SetRandomizationDelayWindow(uint32_t newValue) +{ + uint32_t oldValue = mRandomizationDelayWindow; + if (newValue > kMaxRandomizationDelayWindow) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + mRandomizationDelayWindow = newValue; + if (oldValue != newValue) + { + ChipLogDetail(AppServer, "RandomizationDelayWindow updated to %lu", + static_cast(mRandomizationDelayWindow)); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, RandomizationDelayWindow::Id); + } + return CHIP_NO_ERROR; +} + +/* PREF attributes */ +uint8_t EnergyEvseDelegate::GetNumberOfWeeklyTargets() +{ + return mNumberOfWeeklyTargets; +} +uint8_t EnergyEvseDelegate::GetNumberOfDailyTargets() +{ + return mNumberOfDailyTargets; +} +DataModel::Nullable EnergyEvseDelegate::GetNextChargeStartTime() +{ + return mNextChargeStartTime; +} +DataModel::Nullable EnergyEvseDelegate::GetNextChargeTargetTime() +{ + return mNextChargeTargetTime; +} +DataModel::Nullable EnergyEvseDelegate::GetNextChargeRequiredEnergy() +{ + return mNextChargeRequiredEnergy; +} +DataModel::Nullable EnergyEvseDelegate::GetNextChargeTargetSoC() +{ + return mNextChargeTargetSoC; +} + +/* ApproximateEVEfficiency */ +DataModel::Nullable EnergyEvseDelegate::GetApproximateEVEfficiency() +{ + return mApproximateEVEfficiency; +} + +CHIP_ERROR EnergyEvseDelegate::SetApproximateEVEfficiency(uint16_t newValue) +{ + DataModel::Nullable oldValue = mApproximateEVEfficiency; + + mApproximateEVEfficiency = MakeNullable(newValue); + if ((oldValue.IsNull()) || (oldValue.Value() != newValue)) + { + ChipLogDetail(AppServer, "ApproximateEVEfficiency updated to %d", mApproximateEVEfficiency.Value()); + MatterReportingAttributeChangeCallback(mEndpointId, EnergyEvse::Id, ApproximateEVEfficiency::Id); + } + + return CHIP_NO_ERROR; +} + +/* SOC attributes */ +DataModel::Nullable EnergyEvseDelegate::GetStateOfCharge() +{ + return mStateOfCharge; +} +DataModel::Nullable EnergyEvseDelegate::GetBatteryCapacity() +{ + return mBatteryCapacity; +} + +/* PNC attributes*/ +DataModel::Nullable EnergyEvseDelegate::GetVehicleID() +{ + return mVehicleID; +} + +/* Session SESS attributes */ +DataModel::Nullable EnergyEvseDelegate::GetSessionID() +{ + return mSessionID; +} +DataModel::Nullable EnergyEvseDelegate::GetSessionDuration() +{ + return mSessionDuration; +} +DataModel::Nullable EnergyEvseDelegate::GetSessionEnergyCharged() +{ + return mSessionEnergyCharged; +} +DataModel::Nullable EnergyEvseDelegate::GetSessionEnergyDischarged() +{ + return mSessionEnergyDischarged; +} diff --git a/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp b/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp new file mode 100644 index 00000000000000..0d84d8856212e0 --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp @@ -0,0 +1,33 @@ +/* + * + * 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 + +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::EnergyEvse; + +CHIP_ERROR EnergyEvseManager::Init() +{ + return Instance::Init(); +} + +void EnergyEvseManager::Shutdown() +{ + Instance::Shutdown(); +} diff --git a/examples/energy-management-app/energy-management-common/src/EnergyManagementManager.cpp b/examples/energy-management-app/energy-management-common/src/EnergyManagementManager.cpp new file mode 100644 index 00000000000000..884a5bcf5b65ce --- /dev/null +++ b/examples/energy-management-app/energy-management-common/src/EnergyManagementManager.cpp @@ -0,0 +1,18 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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. + */ diff --git a/examples/energy-management-app/linux/.gn b/examples/energy-management-app/linux/.gn new file mode 100644 index 00000000000000..5d1ce757507582 --- /dev/null +++ b/examples/energy-management-app/linux/.gn @@ -0,0 +1,25 @@ +# Copyright (c) 2020 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/energy-management-app/linux/BUILD.gn b/examples/energy-management-app/linux/BUILD.gn new file mode 100644 index 00000000000000..8597caabfc35b9 --- /dev/null +++ b/examples/energy-management-app/linux/BUILD.gn @@ -0,0 +1,125 @@ +# 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}/build/chip/tools.gni") +import("${chip_root}/src/app/common_flags.gni") +import("${chip_root}/third_party/imgui/imgui.gni") + +assert(chip_build_tools) + +import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") + +if (chip_enable_pw_rpc) { + import("//build_overrides/pigweed.gni") + import("$dir_pw_build/target_types.gni") +} + +config("includes") { + include_dirs = [ + ".", + "include", + ] +} + +executable("chip-energy-management-app") { + sources = [ + "${chip_root}/examples/energy-management-app/energy-management-common/src/EVSEManufacturerImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseDelegateImpl.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyEvseManager.cpp", + "${chip_root}/examples/energy-management-app/energy-management-common/src/EnergyManagementManager.cpp", + "include/CHIPProjectAppConfig.h", + "main.cpp", + ] + + deps = [ + "${chip_root}/examples/energy-management-app/energy-management-common", + "${chip_root}/examples/platform/linux:app-main", + "${chip_root}/src/lib", + ] + + if (chip_examples_enable_imgui_ui) { + deps += [ + "${chip_root}/examples/common/imgui_ui", + "${chip_root}/examples/common/imgui_ui/windows:occupancy_sensing", + "${chip_root}/examples/common/imgui_ui/windows:qrcode", + ] + } + + include_dirs = [ + "include", + "${chip_root}/examples/energy-management-app/energy-management-common/include", + ] + + if (chip_enable_pw_rpc) { + defines = [ + "PW_RPC_ENABLED", + "PW_RPC_ATTRIBUTE_SERVICE=1", + "PW_RPC_BUTTON_SERVICE=1", + "PW_RPC_DESCRIPTOR_SERVICE=1", + "PW_RPC_DEVICE_SERVICE=1", + "PW_RPC_ELEC_SERVICE=1", + "PW_RPC_EVSE_SERVICE=1", + "PW_RPC_LIGHTING_SERVICE=1", + "PW_RPC_TRACING_SERVICE=1", + ] + + sources += [ + "${chip_root}/examples/platform/linux/Rpc.cpp", + "${chip_root}/examples/platform/linux/system_rpc_server.cc", + ] + + deps += [ + "$dir_pw_hdlc:pw_rpc", + "$dir_pw_hdlc:rpc_channel_output", + "$dir_pw_log", + "$dir_pw_rpc:server", + "$dir_pw_rpc/system_server:facade", + "$dir_pw_stream:socket_stream", + "$dir_pw_stream:sys_io_stream", + "$dir_pw_sync:mutex", + "$dir_pw_trace", + "$dir_pw_trace_tokenized", + "$dir_pw_trace_tokenized:trace_rpc_service", + "${chip_root}/config/linux/lib/pw_rpc:pw_rpc", + "${chip_root}/examples/common/pigweed:attributes_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:button_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:descriptor_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:device_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:elec_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:evse_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:lighting_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:rpc_services", + ] + + deps += pw_build_LINK_DEPS + + include_dirs += [ "${chip_root}/examples/common" ] + } else { + # The system_rpc_server.cc file is in pigweed and doesn't compile with + # -Wconversion, remove check for RPC build only. + cflags = [ "-Wconversion" ] + } + + output_dir = root_out_dir +} + +group("linux") { + deps = [ ":chip-energy-management-app" ] +} + +group("default") { + deps = [ ":linux" ] +} diff --git a/examples/energy-management-app/linux/README.md b/examples/energy-management-app/linux/README.md new file mode 100644 index 00000000000000..9671ab073b12a8 --- /dev/null +++ b/examples/energy-management-app/linux/README.md @@ -0,0 +1,143 @@ +# CHIP Linux Energy Management Example + +An example showing the use of CHIP on the Linux. The document will describe how +to build and run CHIP Linux Energy Management Example on Raspberry Pi. This doc +is tested on **Ubuntu for Raspberry Pi Server 20.04 LTS (aarch64)** and **Ubuntu +for Raspberry Pi Desktop 20.10 (aarch64)** + +To cross-compile this example on x64 host and run on **NXP i.MX 8M Mini** +**EVK**, see the associated +[README document](../../../docs/guides/nxp_imx8m_linux_examples.md) for details. + +
+ +- [CHIP Linux Energy Management Example](#chip-linux-energy-management-example) + - [Building](#building) + - [Commandline Arguments](#commandline-arguments) + - [Running the Complete Example on Raspberry Pi 4](#running-the-complete-example-on-raspberry-pi-4) + - [Running RPC console](#running-rpc-console) + - [Device Tracing](#device-tracing) + +
+ +## Building + +- Install tool chain + + $ sudo apt-get install git gcc g++ python pkg-config libssl-dev libdbus-1-dev libglib2.0-dev ninja-build python3-venv python3-dev unzip + +- Build the example application: + + $ cd ~/connectedhomeip/examples/energy-management-app/linux + $ git submodule update --init + $ source third_party/connectedhomeip/scripts/activate.sh + $ gn gen out/debug + $ ninja -C out/debug + +- To delete generated executable, libraries and object files use: + + $ cd ~/connectedhomeip/examples/energy-management-app/linux + $ rm -rf out/ + +- Build the example with pigweed RPC + + $ cd ~/connectedhomeip/examples/energy-management-app/linux + $ git submodule update --init + $ source third_party/connectedhomeip/scripts/activate.sh + $ gn gen out/debug --args='import("//with_pw_rpc.gni")' + $ ninja -C out/debug + +## Commandline arguments + +- `--wifi` + + Enables WiFi management feature. Required for WiFi commissioning. + +- `--thread` + + Enables Thread management feature, requires ot-br-posix dbus daemon running. + Required for Thread commissioning. + +- `--ble-device ` + + Use specific bluetooth interface for BLE advertisement and connections. + + `interface id`: the number after `hci` when listing BLE interfaces by + `hciconfig` command, for example, `--ble-device 1` means using `hci1` + interface. Default: `0`. + +## Running the Complete Example on Raspberry Pi 4 + +> If you want to test Echo protocol, please enable Echo handler +> +> gn gen out/debug --args='chip_app_use_echo=true' +> ninja -C out/debug + +- Prerequisites + + 1. A Raspberry Pi 4 board + 2. A USB Bluetooth Dongle, Ubuntu desktop will send Bluetooth advertisement, + which will block CHIP from connecting via BLE. On Ubuntu server, you need + to install `pi-bluetooth` via APT. + 3. Ubuntu 20.04 or newer image for ARM64 platform. + +- Building + + Follow [Building](#building) section of this document. + +- Running + + - [Optional] Plug USB Bluetooth dongle + + - Plug USB Bluetooth dongle and find its bluetooth device number. The + number after `hci` is the bluetooth device number, `1` in this + example. + + $ hciconfig + hci1: Type: Primary Bus: USB + BD Address: 00:1A:7D:AA:BB:CC ACL MTU: 310:10 SCO MTU: 64:8 + UP RUNNING PSCAN ISCAN + RX bytes:20942 acl:1023 sco:0 events:1140 errors:0 + TX bytes:16559 acl:1011 sco:0 commands:121 errors:0 + + hci0: Type: Primary Bus: UART + BD Address: B8:27:EB:AA:BB:CC ACL MTU: 1021:8 SCO MTU: 64:1 + UP RUNNING PSCAN ISCAN + RX bytes:8609495 acl:14 sco:0 events:217484 errors:0 + TX bytes:92185 acl:20 sco:0 commands:5259 errors:0 + + - Run Linux Energy Management Example App + + $ cd ~/connectedhomeip/examples/energy-management-app/linux + $ sudo out/debug/chip-energy-management-app --ble-device [bluetooth device number] + # In this example, the device we want to use is hci1 + $ sudo out/debug/chip-energy-management-app --ble-device 1 + + - Test the device using ChipDeviceController on your laptop / + workstation etc. + +## Running RPC Console + +- As part of building the example with RPCs enabled the chip_rpc python + interactive console is installed into your venv. The python wheel files are + also created in the output folder: out/debug/chip_rpc_console_wheels. To + install the wheel files without rebuilding: + `pip3 install out/debug/chip_rpc_console_wheels/*.whl` + +- To use the chip-rpc console after it has been installed run: + `chip-console -s localhost:33000 -o //pw_log.out` + +- Then you can Get and Set the Energy Management using the RPCs: + `rpcs.chip.rpc.EnergyManagement.Get()` + +## Device Tracing + +Device tracing is available to analyze the device performance. To turn on +tracing, build with RPC enabled. See [Building with RPC enabled](#building). + +Obtain tracing json file. + +``` + $ ./{PIGWEED_REPO}/pw_trace_tokenized/py/pw_trace_tokenized/get_trace.py -s localhost:33000 \ + -o {OUTPUT_FILE} -t {ELF_FILE} {PIGWEED_REPO}/pw_trace_tokenized/pw_trace_protos/trace_rpc.proto +``` diff --git a/examples/energy-management-app/linux/args.gni b/examples/energy-management-app/linux/args.gni new file mode 100644 index 00000000000000..cca4c8f39e09fe --- /dev/null +++ b/examples/energy-management-app/linux/args.gni @@ -0,0 +1,31 @@ +# 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. + +# CHIPProjectConfig.h + +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/energy-management-app/linux/include" ] +chip_project_config_include_dirs += [ "${chip_root}/config/standalone" ] + +matter_enable_tracing_support = true + +chip_enable_read_client = false diff --git a/examples/energy-management-app/linux/build_overrides b/examples/energy-management-app/linux/build_overrides new file mode 120000 index 00000000000000..e578e73312ebd1 --- /dev/null +++ b/examples/energy-management-app/linux/build_overrides @@ -0,0 +1 @@ +../../build_overrides \ No newline at end of file diff --git a/examples/energy-management-app/linux/include/CHIPProjectAppConfig.h b/examples/energy-management-app/linux/include/CHIPProjectAppConfig.h new file mode 100644 index 00000000000000..f22628d0f69def --- /dev/null +++ b/examples/energy-management-app/linux/include/CHIPProjectAppConfig.h @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2020 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 + +// include the CHIPProjectConfig from config/standalone +#include + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 0 + +// Bulbs do not typically use this - enabled so we can use shell to discover commissioners +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT 1 + +#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE 1 + +// TODO We don’t have one yet - but we’d need to change this +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 257 // 0x0101 = 257 = Dimmable Bulb + +#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME 1 + +#define CHIP_DEVICE_ENABLE_PORT_PARAMS 1 + +#define CHIP_DEVICE_CONFIG_DEVICE_NAME "Test Energy Management" diff --git a/examples/energy-management-app/linux/main.cpp b/examples/energy-management-app/linux/main.cpp new file mode 100644 index 00000000000000..dddc6f53d76b20 --- /dev/null +++ b/examples/energy-management-app/linux/main.cpp @@ -0,0 +1,144 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define ENERGY_EVSE_ENDPOINT 1 + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; + +static EnergyEvseDelegate * gDelegate = nullptr; +static EnergyEvseManager * gInstance = nullptr; +static EVSEManufacturer * gEvseManufacturer = nullptr; + +void ApplicationInit() +{ + CHIP_ERROR err; + + if ((gDelegate != nullptr) || (gInstance != nullptr) || (gEvseManufacturer != nullptr)) + { + ChipLogError(AppServer, "EVSE Instance or Delegate, EvseManufacturer already exist."); + return; + } + + gDelegate = new EnergyEvseDelegate(); + if (gDelegate == nullptr) + { + ChipLogError(AppServer, "Failed to allocate memory for EnergyEvseDelegate"); + return; + } + + /* Manufacturer may optionally not support all features, commands & attributes */ + gInstance = + new EnergyEvseManager(EndpointId(ENERGY_EVSE_ENDPOINT), *gDelegate, + BitMask( + EnergyEvse::Feature::kChargingPreferences, EnergyEvse::Feature::kPlugAndCharge, + EnergyEvse::Feature::kRfid, EnergyEvse::Feature::kSoCReporting, EnergyEvse::Feature::kV2x), + BitMask(OptionalAttributes::kSupportsUserMaximumChargingCurrent, + OptionalAttributes::kSupportsRandomizationWindow, + OptionalAttributes::kSupportsApproximateEvEfficiency), + BitMask(OptionalCommands::kSupportsStartDiagnostics)); + + if (gInstance == nullptr) + { + ChipLogError(AppServer, "Failed to allocate memory for EnergyEvseManager"); + delete gDelegate; + gDelegate = nullptr; + return; + } + + err = gInstance->Init(); /* Register Attribute & Command handlers */ + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Init failed on gInstance"); + delete gInstance; + delete gDelegate; + gInstance = nullptr; + gDelegate = nullptr; + return; + } + + /* Now create EVSEManufacturer*/ + gEvseManufacturer = new EVSEManufacturer(); + if (gEvseManufacturer == nullptr) + { + ChipLogError(AppServer, "Failed to allocate memory for EvseManufacturer"); + delete gInstance; + delete gDelegate; + gInstance = nullptr; + gDelegate = nullptr; + return; + } + + /* Call Manufacturer specific init */ + err = gEvseManufacturer->Init(gInstance); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Init failed on gEvseManufacturer"); + delete gEvseManufacturer; + delete gInstance; + delete gDelegate; + gEvseManufacturer = nullptr; + gInstance = nullptr; + gDelegate = nullptr; + return; + } +} + +void ApplicationShutdown() +{ + ChipLogDetail(AppServer, "Energy Management App: ApplicationShutdown()"); + + /* Shutdown the EVSEManufacturer*/ + gEvseManufacturer->Shutdown(gInstance); + + /* Shutdown the Instance - deregister attribute & command handler */ + gInstance->Shutdown(); + + delete gEvseManufacturer; + delete gInstance; + delete gDelegate; + gEvseManufacturer = nullptr; + gInstance = nullptr; + gDelegate = nullptr; +} + +int main(int argc, char * argv[]) +{ + if (ChipLinuxAppInit(argc, argv) != 0) + { + return -1; + } + + ChipLinuxAppMainLoop(); + + return 0; +} diff --git a/examples/energy-management-app/linux/third_party/connectedhomeip b/examples/energy-management-app/linux/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/energy-management-app/linux/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/src/app/zap-templates/zcl/data-model/chip/chip-types.xml b/src/app/zap-templates/zcl/data-model/chip/chip-types.xml index 02d81623cc3394..cae3f4a87df8c0 100644 --- a/src/app/zap-templates/zcl/data-model/chip/chip-types.xml +++ b/src/app/zap-templates/zcl/data-model/chip/chip-types.xml @@ -55,10 +55,10 @@ limitations under the License. - - - - + + + + diff --git a/src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml index f8925c73d7ce3c..df911627b297dc 100644 --- a/src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/energy-evse-cluster.xml @@ -169,11 +169,11 @@ limitations under the License. The GetTargetsResponse is sent in response to the GetTargets Command. - + EVConnected - + EVNotDetected @@ -181,27 +181,27 @@ limitations under the License. - + EnergyTransferStarted - + EnergyTransferStopped - + Fault - + RFID diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 71dfbb1e03a9b8..0ab3cd79e655bb 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -7238,8 +7238,8 @@ class EnergyEvseEnableCharging : public ClusterCommand EnergyEvseEnableCharging(CredentialIssuerCommands * credsIssuerConfig) : ClusterCommand("enable-charging", credsIssuerConfig) { AddArgument("ChargingEnabledUntil", 0, UINT32_MAX, &mRequest.chargingEnabledUntil); - AddArgument("MinimumChargeCurrent", 0, UINT64_MAX, &mRequest.minimumChargeCurrent); - AddArgument("MaximumChargeCurrent", 0, UINT64_MAX, &mRequest.maximumChargeCurrent); + AddArgument("MinimumChargeCurrent", INT64_MIN, INT64_MAX, &mRequest.minimumChargeCurrent); + AddArgument("MaximumChargeCurrent", INT64_MIN, INT64_MAX, &mRequest.maximumChargeCurrent); ClusterCommand::AddArguments(); } @@ -7278,7 +7278,7 @@ class EnergyEvseEnableDischarging : public ClusterCommand ClusterCommand("enable-discharging", credsIssuerConfig) { AddArgument("DischargingEnabledUntil", 0, UINT32_MAX, &mRequest.dischargingEnabledUntil); - AddArgument("MaximumDischargeCurrent", 0, UINT64_MAX, &mRequest.maximumDischargeCurrent); + AddArgument("MaximumDischargeCurrent", INT64_MIN, INT64_MAX, &mRequest.maximumDischargeCurrent); ClusterCommand::AddArguments(); } @@ -19708,16 +19708,18 @@ void registerClusterEnergyEvse(Commands & commands, CredentialIssuerCommands * c make_unique>>(Id, "discharging-enabled-until", 0, UINT32_MAX, Attributes::DischargingEnabledUntil::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>(Id, "circuit-capacity", 0, UINT64_MAX, Attributes::CircuitCapacity::Id, + make_unique>(Id, "circuit-capacity", INT64_MIN, INT64_MAX, Attributes::CircuitCapacity::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>(Id, "minimum-charge-current", 0, UINT64_MAX, Attributes::MinimumChargeCurrent::Id, - WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>(Id, "maximum-charge-current", 0, UINT64_MAX, Attributes::MaximumChargeCurrent::Id, - WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>(Id, "maximum-discharge-current", 0, UINT64_MAX, + make_unique>(Id, "minimum-charge-current", INT64_MIN, INT64_MAX, + Attributes::MinimumChargeCurrent::Id, WriteCommandType::kForceWrite, + credsIssuerConfig), // + make_unique>(Id, "maximum-charge-current", INT64_MIN, INT64_MAX, + Attributes::MaximumChargeCurrent::Id, WriteCommandType::kForceWrite, + credsIssuerConfig), // + make_unique>(Id, "maximum-discharge-current", INT64_MIN, INT64_MAX, Attributes::MaximumDischargeCurrent::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>(Id, "user-maximum-charge-current", 0, UINT64_MAX, + make_unique>(Id, "user-maximum-charge-current", INT64_MIN, INT64_MAX, Attributes::UserMaximumChargeCurrent::Id, WriteCommandType::kWrite, credsIssuerConfig), // make_unique>(Id, "randomization-delay-window", 0, UINT32_MAX, @@ -19733,8 +19735,8 @@ void registerClusterEnergyEvse(Commands & commands, CredentialIssuerCommands * c make_unique>>(Id, "next-charge-target-time", 0, UINT32_MAX, Attributes::NextChargeTargetTime::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>(Id, "next-charge-required-energy", 0, UINT64_MAX, - Attributes::NextChargeRequiredEnergy::Id, + make_unique>>(Id, "next-charge-required-energy", INT64_MIN, + INT64_MAX, Attributes::NextChargeRequiredEnergy::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>( Id, "next-charge-target-so-c", 0, UINT8_MAX, Attributes::NextChargeTargetSoC::Id, WriteCommandType::kForceWrite, @@ -19745,7 +19747,7 @@ void registerClusterEnergyEvse(Commands & commands, CredentialIssuerCommands * c make_unique>>( Id, "state-of-charge", 0, UINT8_MAX, Attributes::StateOfCharge::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>(Id, "battery-capacity", 0, UINT64_MAX, + make_unique>>(Id, "battery-capacity", INT64_MIN, INT64_MAX, Attributes::BatteryCapacity::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>( @@ -19755,10 +19757,10 @@ void registerClusterEnergyEvse(Commands & commands, CredentialIssuerCommands * c make_unique>>(Id, "session-duration", 0, UINT32_MAX, Attributes::SessionDuration::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>(Id, "session-energy-charged", 0, UINT64_MAX, + make_unique>>(Id, "session-energy-charged", INT64_MIN, INT64_MAX, Attributes::SessionEnergyCharged::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>(Id, "session-energy-discharged", 0, UINT64_MAX, + make_unique>>(Id, "session-energy-discharged", INT64_MIN, INT64_MAX, Attributes::SessionEnergyDischarged::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>( diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 14133801e0836b..ee479487347d1b 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -80277,10 +80277,10 @@ class EnergyEvseEnableCharging : public ClusterCommand { AddArgument("ChargingEnabledUntil", 0, UINT32_MAX, &mRequest.chargingEnabledUntil); #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - AddArgument("MinimumChargeCurrent", 0, UINT64_MAX, &mRequest.minimumChargeCurrent); + AddArgument("MinimumChargeCurrent", INT64_MIN, INT64_MAX, &mRequest.minimumChargeCurrent); #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - AddArgument("MaximumChargeCurrent", 0, UINT64_MAX, &mRequest.maximumChargeCurrent); + AddArgument("MaximumChargeCurrent", INT64_MIN, INT64_MAX, &mRequest.maximumChargeCurrent); #endif // MTR_ENABLE_PROVISIONAL ClusterCommand::AddArguments(); } @@ -80346,7 +80346,7 @@ class EnergyEvseEnableDischarging : public ClusterCommand { AddArgument("DischargingEnabledUntil", 0, UINT32_MAX, &mRequest.dischargingEnabledUntil); #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - AddArgument("MaximumDischargeCurrent", 0, UINT64_MAX, &mRequest.maximumDischargeCurrent); + AddArgument("MaximumDischargeCurrent", INT64_MIN, INT64_MAX, &mRequest.maximumDischargeCurrent); #endif // MTR_ENABLE_PROVISIONAL ClusterCommand::AddArguments(); } @@ -81438,7 +81438,7 @@ class WriteEnergyEvseUserMaximumChargeCurrent : public WriteAttribute { : WriteAttribute("user-maximum-charge-current") { AddArgument("attr-name", "user-maximum-charge-current"); - AddArgument("attr-value", 0, UINT64_MAX, &mValue); + AddArgument("attr-value", INT64_MIN, INT64_MAX, &mValue); WriteAttribute::AddArguments(); } From 9310a374cb3d728245b6b99004f3f3727a5ed565 Mon Sep 17 00:00:00 2001 From: William Date: Mon, 18 Dec 2023 13:12:45 +0000 Subject: [PATCH 2/8] Update rvc example to handel new pause compatible states (#30963) * Updated the RVC example app to appropriatly handel the RvcOpState Pasue and Resume commands for the new pause and resume compatible states. * Updated the RVC example app's state machine diagram. * Restyled by clang-format * Added some clarifying comments to the RvcDevice pause and resume commands handle methods. Renamed variable for clarity. Removed unnecessary temp hold of pause state. * Restyled by clang-format * Changed the naming to note the state that was paused rather than the state that we will resume to as we cannot know the state that the device will resume to when the pause command is handled. * Clarified comments following reviews. * Modified the resume callback logic to be more concise. * Restyled by clang-format --------- Co-authored-by: Restyled.io Co-authored-by: chrismapp <42716253+chrismapp@users.noreply.github.com> --- examples/rvc-app/RVC_app_state_diagram.png | Bin 244472 -> 279372 bytes .../rvc-app/RVC_app_state_diagram_drawio.xml | 2 +- .../rvc-app/rvc-common/include/rvc-device.h | 2 + .../rvc-app/rvc-common/src/rvc-device.cpp | 47 ++++++++++++------ 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/examples/rvc-app/RVC_app_state_diagram.png b/examples/rvc-app/RVC_app_state_diagram.png index 5b8cd90807bae74b416e1b4f0525162b2332a28d..a7cf3175aa87ba605214bbb4ca456c8909d3944e 100644 GIT binary patch literal 279372 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

ZGF)cde+s|`!7&P>P=0(4g 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

h$oq|pT%1vbFh_CjUGoX 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%0D!-M%NSv-SA(dw- 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 literal 244472 zcmce;byQW|8a@gLN{5t`AWD~Xhkzp8-5}j59U@4hBHhy684MT5GO%zWF@QBuGw13=NqO83qOhP5iZ}0t^gN5)2GHJK}xte}*j% zo54S@4hmwzFh#w@>o726Fyf*wlw5SSW*(?1s@^`>W5N{Tcvo#VT-O@puCxg`ak8

b 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

+(3yDW_fUSOZ~Zw?^RcGoMpr=l z#KbsgiACrX{KzNgLWXoI3}TU*2w&zls;YC_a==!MGkm4T#sJP2X$1WoEm}Ud{k16; z*IPc!ye(;SyPyxuySD$sY&zogRH!P_2(NxPtvjd|_1e5|_p!XFY;;!_`aXdj4~V>> z_8-H#y#tc_JWs;MN)Yw-z4u5DoCDD~M>XM~WDKblpu5`sgh}1mLG4$P!*coyf;Uft zWWv3c(%l&#C7@hZ4>`!`)vv9sl0t5)@i1^n^Gw(KelS~t13`%j$1qy+&Ly&|gqhD^EoJ(^9>LNl8+lOq27xWLc%;_P75)$mI# z>E$2RzQE_DJU(2MCgm#vGH{;3GH7&IHTa6twGKq0 z1Wz+yewx-0;0a4jgree@Tud&-m~7c*7eykn>XTA-`nHG;ACAGk9TuMeC?nw57ELdxjA(04<#Uy`;%1u3F~T+G14!$rAHd?(FFz0V00 z2N@?L&P$BbD9I1@V~M~mSal9WkRDNQf>s=d^ZH6b?8#;gZeyCxSbzm&cuU9~g37zn z00@1oX5aq?tDfYwq&qYa12$(;YOTiL4|R+eLMqB6uAWl|obW*B1hrpRSCF4l4bwud z*4dDF2jnc5Sj{d)A^|m0W^D;DDI+Tun@mV>J&v(g;|tU_r+j?^on~fPcB4SEIuC?V z+PaPRKiPo~Q3<2%eouqgB-vzm%7D;)_k4FO)}pk6G|dOnA~!PU{6vLC^R zFV>_r|2_rFT2w?zPAWMqE#oGrs0V6BZ*-bU)Pn}0|NE??RSL~WLwS8I3O8U@S6GpK zA`I+fG>6_&6=(TTphgX%z*559k+-Ub_VO;!l2+UEU8`d6r4qQqUl*A_Hsric!odQJ zs2_;h?mxxTUHbFTWr*x+JrE)nA82agB`kacP7gZxVcmq^^5LX}a5#C`G{Ico9~vv21PNSG8}UDbDt|LA(pW3R zTvry>jC?)6AaICRk5m42?(A@B_+S{M@?gvTQs)C&T3Y@Jg}9#kYS(o?RA0@yuKVTw z#I?Y4ywJ?k)fPtXQ1@R)$kmi=b=f(VxHFAH*4Lxu11i`W8kN0>pH^zLZN5sFXDU zzmHa}lX)B7&Ee|2z1Mynyx;|B-<+r})@X2BW8$+LdEaIFl6psyPgsW!$T4-~FAJ#o z$b^G7sD*I_?M%PgBDjR0(wCO>?Tk<<5mnJNP}wR$Ip9aVakV)xYSE`WVze{2aPu8#wjOn>hu_6;!&IudAfwzgAxS<|mQErwrwc0DvNI zAfPvh5yHjzvAwM1FCagT8+Yw$EKb0MM6kC8vtr@TfffwI5B5iRmdsdc1hF&iC}@UsSl0OzRq}+|H%Htl(TqNCVAQ?TVmjrF8~ zt$Wo}uc2x_Gy*jT3pq2_Rp;=oQ*_LldCB~c!W|mxXkNp)*qcqbuKDN@`rd`tH<8K| z2S!Dk7dD*vWLs%0`F1oUHN^g?y!~tR5(Lq#Xt!=9mEw}$D*)O_Lr7SbXy&V@f5xK_ zbP^O4tkosS|NNKc68bNixB5Ux=DBX{t9rmGme(P0*7d9ZRoX;)=ipcXMdk17*nREa z-*A+2boP$lmxvl|UzAK7A`*1+pgwDIVLihiN~wO!I#NhE_@qL1l?z59gIYAXw$bu zeQ+456$;mA5bBd6!x}c@W}g)J=W%xA0O38*sHv$3-NK{t=lku1vtCC9?j9W6;@RDp zGNpLlr4WM$#Gw>bg}29VhDSw>xKRx&*=)Ecs&qxQ-684L7Y06!G=e!)M+C(6)9|Rp z)ACU59d3E?^{9>*d0E+Sz>h3$mY9Lcdl=^kWc8*+jli(0!co6+^}6f064#xT@DLH} z);XX}MqQkr;V(u+M&u5JX=OC_do&_GzcV_C6#mZ|iaL zxKLaeizxq~GRZDC#EI9|e<>%8&arH0@G!PCC_<1kPR`_GqY#UYuijQZ(bXJYMjdP( zBElSAT>Hz4HsmaKwc>Hn8dc-fSP2w`p*~lsN=#pPZrx;DioNs``XDrfwk5ey76aFM zj88nBUq;kmZ-$tNvjE%r=iJ+@xvV5LhshmLxa)b=4i4(bC=~z$eome+-p4F2lD#AjXHAj0f{rbzZ>gJ+?ru`zNn(yRskB`^NL(JMI`oKgm%CaUFquzld zGXjLjTR-B{hoLq|HviuGdfO1mQlW^+4tNM%#v_N#{7-+~2PM%)(OV9)9#dlbCpSK{ zcLb8K-1na})wp%CIrF6ug3-Ia=|^jz|D zIlT4+Aq4Qiqou7FRTXUvvO>M3Xe=-`@ACNC```NaS^$eiry5%`P2^&d8a7ovqg7LlL?F4GK%Hn#D^P*~W>P_F<#t^NGk8oR?1 z{aphll_&ZJ24Oz67G$ptID%H{BUaXD`b{`0cy6tCw@c7t;o&hw=E9xLR>GAG!;>fk zUv32EGHnS(&cMK<`RQp%j?fB%&WRRCt4Ra&?}V9f% zr}ZW@G!)+GLAha#GRmGE$f0VU{(eB=SZ_aecb3zx{uAXipf&paTN_m)S5 zNobEe?kD269L`>+z31XCu>Kx%MfHsziKW#8I_Sh@zlt{Qt(!LVi=rQ!kd8BOHGdvuJ zlKutoa|PJjvqf%QH|5aTssW8dzbk87g*f$QF6=59t6*+Bp303Sk+_(6~ z`64i>BMcB8esAR@&O5{4`2MfZrhKWy7njX-;bn zl?njQ9(NkjRr;Do6`X=e~*nBC_doO&ZQ7Wi<0P2uz{j4txiW)1!#dT z07{WU5=YQ>)n0pcTYQTL5UkP$5`#7)n5TNHG9^8ovaP-S)jJ+)ai3({m2e@KzqP!# zdrTXtenjm&>feY01B*5G8nfebrP2NS(FAKA%aMW$QAfV(W_rNaM;qpRz%L=u;-2?s zyp9(TnxaqS0S@ny*w-Hws_j7+{jroAWc^2gyys_U>CQWLcD7Q-mGFlQihg(HWCo+G zwN7KXB9~;l2rbYE6qzoq;H08qNJ8_xk+HG6fbGzH9LT-2U|h1tk22#gK+)k!$HG!j z_*KQ+i{KKP6%mL-Z#}KuO++pN>FBPE!FQN`57E4L$CeZxZjFR*2hh>WjS;l=$d1LM z2joB+E#=gXupr`O z;ODS6XGGarDusoxCB_0XzZ`QpL}OkbX+1kqX74!=adBQ^7q5(2nu{^KRRaT8wNYd$ zj!u{YkqQF(yT?ErSg2p|$kM_>21=A}kdm_0yEbvfJByFcL@0FAD^8h~LvhGRjuJ7O z{`8&aAvhRg%PsK&DtXU8#dFlT z{rMSFy8|~wGO2I*u;Nijr>1~DH_%)2@$fcB%C$he<&~+h`O11-TderVQV>gT}8rNOXCS|U>!vXkYg29WT70%kKNMmhCv~qaxW$MaG z@1`oQ5PgO_t`f1UlH8?%Fs+!jMw(4pmP?2%_Xm`clS5PtKbW_RC0}9-B7KAv zFo8lFY*&Qp4fMn-Xav#J@H5-R*mSWkFHxrkWKjoz9%nYiT2Ym-u2nWcHd9RXl1UAL zG4F*oiPSI4$-k%PZO(`Ww3G#l>gS5ELxlhjDr`g1pWPU@yrkfG~0x z)`+W0aV-%O)`*F$vEXtxH#&TAEb{`DC&6ySssU@7H@GFchX&sz|9Qg$JO96WwU>ts z+Uxq0d4lYpK4qn$kwlqE08@E8GtUrZG$gHr<9en&1>&ZiQZ=!sg$4_1E0Wt0EpT{M z@|cF^3Yvhx#~{ctmF%}%oDG<~I^wZu$M)G9)r$eg++wT5w|%3X5>A|r9&Xg?ikz@5 zapz0agGLYM?frd{IJI=)1i(S>?5g2d^P$%0HO0x^nnHBHj!Ch}@szE`Cq|R{cU&{c0< zGKhHx@Z19><&kI2!efMwP7}?995pg4sjv~IuVUHUonQt{5D9MgP92nwYFLreeMSdi z$hhRo$t-43LPLzsk)FV+{o*Pfg<@i2BDE|SIzEUr<1sQYB+Cl(3JBcdVPs+=PbU>l zC!-W1iBAS$4MVf=k|Fd*S+m66&A{ZEu{5Fx&J#xWNGYg~ExJpqXj8<&9*d5qM%=nn zme*6BJinDzkgP>}|37R6LG)!bclU#Lpx;XyAp;>I^ficdi0K?ScgX$U<)?1iGs*PkyA6JmhAzKmhwmoysTf4uj zB9e^v#rD#GhLV!f?(T~AtegH@i;4&ZNR2+;v8E^w+n}{V{QE!0wk!|`BWL0N|95h< zW}iMAz|>*(I}nn3z$!)GFMt7_<*g?3FIUq&5-)Kg5{OtC-dy=?ztb&DPft&5f^pjL zh4LqGZ|4k?ZJ0rb9ngY;`5q#Ji3 zQu}(KV*cih8}W^RIO2kr+lFrW`NHfr)W)P(Wo0GNtN{vDT?@m(BS)%jwYPYBtT>sa-Y?x`bsJehCcR*5}b{Oq-xcH6bx3dzHid z%GIlRDQe0q2!yJJGgm?)GOXM=pO@q-YA%%8 zmqtTFV@pr`(GJ*y!gd}=$*~#LavzLjn9H<9Iaru1SD~>L~8Nl^L#vddNmR4Ia ztCA?s(B$*k^9|-z{l5{lk!a{Hj35|g2~tL^pnt#k!kOH^jaDPNQRewaWltIMK2H?> zIXc<)7lT<();fE3`mjk!;e>|}pnS))7Z2Tz(QE;X_t&1D;?Dq!Y13F6yOC5HR4Vkf zL9R&Lj#qtVg~kW$Q54AgzO#I-G$TgsyJYp+W0<|N0&vgPI#Ek_&f?yYpc)mUa{OCD zdij@8bqznE3OfYrdyy`CkzP5Kkg)Gz5bOH;_K5*hkVxj1X4<$=gh+TUACR?k)JJbM ziH15jVe&_6FsJJlYRRF@R2*TvUNCUPC2}OSwY3cb%8PR}Co2aXGrIwHw{nIr141AX zj+Yj4@K;oYYPwN5cAnUnD;&cQFA0#xfNaozZr4fyuYzNE*@+&@-(MBGV8PQp|H4#f zyy~u}VAGMDCe9v#2ibA5gP6ENpKFs)0{Ufueue-@au!~XNl8XvluV3|M*;w>JB56W z?Ynl2n&e?{%O0Jco^pcVe5cLUzjIfzpXMzsf~<7xOY^%aJ0Sf}$Gsd`Ji;@xZn?F! z6(7C17`zhy525P{#2u)8OqkR8K;emBoVq%PFTl6jD$;#?tijD`6SGx9%DJ*&0%N`b z$@=3&dIdbMi~0lL+*5GK5OI$@6#RD30V;4A2oXmh5?}Q2BPV!qLr}{d%k^ZkQ3ytc znVg+D9-w#|ag9-Z5M%kbNmt?mvS(FH_>j!vdAW;k$I{TaCFYNlYXSOzLSYiyUx3 zF3c6xIaOd0z5zTQnjcW`UxbJ=#Y~ri=eFWs54H6-?GwWuP68h<&QG}dgzAQGQ&)5a zE!4m~)-7kS#s$F2Jv(=h%S*D7+y&_WUX@;S!8SZ3ZC_lzSTxx74Z}NJGvCEBq-sgRj({8=Gd{j#GMWL4*IaQf9`68OPgy?pjlh1EBr;|u^KsjJsOGV+iIsT)cY7@>Wi;IiWg2)ixWY#Q1F+lX#`-T2p6x zw+a2Iw%;2b=a}lVS*=wQCytamsD(kJ(eNyD=JX8+ie5dhvzxZ4_xGh({n}N#4_?H zHX)Ha@{Ej(8w3QB&_|UAiu3itZbH9)v%pCEbf{X27e)(r<2o}n$&q}Ujs>1%X_CK zm!XS5^8o@asqNFl`1^l#J#jjyf`H^^zAq>wG#017-x)F8XuQXb2ts@6K(SX0 zCU^6vUMuhNsbq7pu~C2)-S*iJ2Zzi;LPCcP;NP@C`BdIZi2O4&Rd6!ZXI=9Pb3CZi z21sq`D?=u`rQhZ5pWyu8C23>9Bjd1NH+Xx!SFLW|=z-XlJF{TPmW_eyyg6Y^L~B|2 ziT2s(vL(yRS0I?rC9RH!azTOugMWhpcQce#R+!xj7AS}NS;}oG z>D>sg3c*k4WQqDAEp3dhs&w7&ps+{)u0{jbWByJ%`}GZQQnGAncl>wzg%QTqwtFpL z{vR6dI&Sl}pzqzgcRWuXPz+Yddi(8bh(i-nQj{U;EP`kor!B%lyNDVH|M}3XIfMXM z;Y%<{rQ7yt#6@1lO%N<@`eh)2o2+pY3yqehF9Ec|CXs&A5Dz2MvoIxa6ze+c%SyJ_ zuAgO9Mqtd0$IctBmz6WYi-OEDkt)oH{bj6385@ExqfC2_x2iX)R`+d?LT~uZvRiv0 z-p|xAxrIEz?-EV&*~^=GcS*Y~FyODU=O|+l!B3Mzf7pA|8%l?7q;^je|2l`(4?MTl zj-AV{e`zHAi4QLcH>o{qVy&eo8NO8}?7LvzY;h%M@-AEMAwVU%O;8 z(a$9hfEp%)Slg|@KwTubR4ovoV@1Gk48f+yjdTI2WeOQNz6Ij9bKI46RM7ZlHh;ks}4qdFO ztDb;du&1Xd6l5|LNLbW!U=nYW2j0iu_5SK&i=vS7v6^q~RHpco78Vs1#q@#z#NmJ^ zz)nP67X4Y*($5jlay5??Y0;TfS%(r%A7F7YM*-umlLuM`eYLf9QNzKd4^WL1dO9c(p2EU(W-T|(zt~tp(79${a9v^*H(36M(4jJ1D|9`Fv zp9&y0EN$%TLa&-0PcNTHyx1+_p?{Fu2K9}jpe8I-$`xqDX zo)uQ^P*DCH{Y`t+q_N0XfL43h^$NQ+MHa1LL&wT3v>*n^hrm!5fQon@V5$bm%F3>l zl#d)UkgC}Muu%w*Zu7fsxR$w%UC(v$p38?4w|5!4Jtd-r6Ln1^l}~~CX-`$UGt8=e z1ki>OSDV{YVp=%F?7(GFX@9l^NzU^Fu*5UooLTJRl*|;U%142>5F`*!sW0~oN;Q7q zBD>eMJHTi3KE8<^DPCs|_TBTwa&!R|1l5e;K9LC8Td8c7$pxM#Ng+_R&g>4)=Z98* z9D3t@KIH7JE*Z>~o~*Q(!{n3y1JDLvjDl)60<+; z(h{n*t2Pfnb7-D09EdFc(=^d8j#VpbjV9idhg$IVby=M4jaR0N@}`hu(Lr*ykr(0` zWP-&892_z~WxGPg=(`t?_kX5rNgE30IsRe=b)n&+TAlc<)pg5mnHOfc7i_BUCY`ly z&yhiW9xh);f=33w`y5}4R34#Ys&tX~^!75LFktB>=nn^PN_u}7%`1ip;1*CRq~|TB zqM9-5-c1&Zi}y(Ogx+p^r6=7ER_+5F(p0gpVWraa{Al+IS18W|eS%dhV01*SaPj_n z#5>c9n-~ZdllR;R%W*gt6V@giiISY5j|Wn&NXU2M%5ez@iommCh2DV^R{Y7L-29rG z^$MK0?ze9rBE!7Dz@gmX&1gsmhLtRZO>699%N8d&|7^b1 zhZXv7#y}Va#0X+WDX;q-XD|woElW^!kkmx*VASpV*k0UAXfpzFm5*UUa$WovHmvFk zx@iV9=Oz^js2z3JH?q6ACECxT*5OD6Ux2FxVAbvWpFVyJ70){C`c$O)0-m|Q>j~sC zY8C;9%-<#|AEgPqXhK+10CbYDdfoRnP=?NhNN(f_F2xAhd|X@{>E!~Lp(o@9A-eD! z?JLR%mn(OOV@6E)^d3E9|9*$T=5Q%f6rwH?l91?VR&jChu<&qxH>PzS$b83^Wn3K) zlS?uh%;{3y)@8xl;Pv$ASNlYQfv-TL(*A&%4{s>JttvxE~@pJHH}KG>(5^}d&O zyRJ5WK~o=3guf7A+-^L$k*Uvu{iLPM&@+IuMFX9qr5&hpw+kPC7>OIu?W83mV~*;S z2so;X8LqozeETx@Iu{d@JoRWQP(>Lcj7>~Hk8Utq+{+oTZb9H|h2oI1Nh2m73f#>e zvq0DgZOpt6SbYuj{9m`4KNJVrPxCP#dK}Ntd+!LOnEJD&vODvv z?T~JPP-?<*yo5Iw7$(Gd_k5Jwa7XOuCYh{15+04V8lQB{{? zQeu?FPee1W-ZUBadQivJs7yqN1uT&ECi3S0Z~@k|q;W?mN3p^mD6Cq1%cB@3c7>!*R{|Jan;@-j%5)9ujpk2t)7*?&%wpXr#U=aHcR7wX`2c|FgDffOv`p|p zwl(ufHAKUt*+BGWe9V9Dq}dbbc6<;plY;mAo!M}-H>$M<^GmT{Ug+%Q4*($p${f$2$cGFg$$NE5z&aX*=AS_>gU4zl)kcog6 zH!v^`FbP<%6#11pp3(50-Q_51KtYl^lTmnIz`5 z$#uLsKTnUoGEf3QYz@Hp0`F9`#1<*uL4KOII+%?RFBHbB6Oiik^#WBg_j~sWVNl>G z_+dS>RY*&6FQ;w#N=C(7z486Q@zSg@35c7D00$6zu-&Pc5Vjl0xY5?u2G_n|WI^do zDr@T)F>W#mt0w7!waJ{_4D(P|*Hd6x3pY_b@+=g7(Pxge&Q-nSN{3|)U|BU6s{I>% z%wG)lzsj1pO6B|IqlG4#=UE#|)$>yP>USqcyQlZ~Rv4P1F62Bva8*?fGgLpqx=xGc z>f`De;JYMxqcQ%e2F80w3%tz!B^@gHSOpZ(GaXOQ-F1pN^<(OnzpA>4UjrQ5{WNea zpP%NiJs<5$>=S;JN2l#N`y89$~zW;tl zs8lr6Bj}~z6hW020`pG#nD{5vaIQ&z!wlib$}E|20D$_zl8=H+z&b1gB>3MwQv+x6nlUKz2saK)J3%xiCAPht6!U|@CMo*N z)H22OQoMEbBpVrR69lNh)mMxv1asSWeW}v<9NdOp`m4<5&Gs8;_o&f4!SG6Xq?+%44Ym=16*xk zPZcMxgR-4!smVDjbBTNXV7y_ih(F z^o&6vzmEm`S3v{_AbjW|j{6S~AQ@xQpHw5ChUGTi0zv%5p$g$6WAz(gpgC-x{O$xGg$dhGsOFifv%CG zC&0D4tQf&|1a8Wn)zSL)brckHIq5unzrXa}?|U9@#hXVwq+-|H+`Ld{B*}6Q3K+6X zivxBI+hEawwew}902eH81k`e*4Gaw0XGe_WZ@ls5{joWFX(V+o@v$ch6j9-YkR^=7 zK#hQtV4=Cu=cEnmix;Ms72m&W{^^=sz|VSps$`EiyT>6o$dXI98leX^o2Y*+=(M(C zG|whqa?~h2iyS;%!1-AOZ}mYj_YCSi5*`@;kgcJQF-G|qi|p?2Ul9ONvc7?!-_p`N zD6lU~78Y~A0nsh;oqZfmssuG?NQxtK^YYli%XiyCg`fz+Le|yYW>13}d!2t1K!6Qva

iT5v`)a0jDr8JPgvSMg4eUv&e+Lt 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

VB5K+@99D0yh|GS2WF+8?8eo1iivq` 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 He)N9;L!7IC diff --git a/examples/rvc-app/RVC_app_state_diagram_drawio.xml b/examples/rvc-app/RVC_app_state_diagram_drawio.xml index 69b82a62543f48..d4f9479b557658 100644 --- a/examples/rvc-app/RVC_app_state_diagram_drawio.xml +++ b/examples/rvc-app/RVC_app_state_diagram_drawio.xml @@ -1,2 +1,2 @@ -7V3bd6K6Gv9rutbZD7qAcH1Uazud6W3ZzpnT87IXQlRaFAdotfPX7wQTrkFRA7qrMw+VJISQ7/b7vnwJF6A3XV775nxy59nQvZAEe3kBLi8kSdIEEf3BJZ+rEqCQgrHv2KuiVMGT8weSQoGUvjs2DDINQ89zQ2eeLbS82QxaYabM9H1vkW028tzsU+fmmDxRSAqeLNOFhWa/HDucrEp1SUvKv0FnPKFPFlVjVTM1aWPScTAxbW+RKgL9C9DzPS9c/Zoue9DFk0fnZXXfVUltPDAfzsIqN3xqi97rpDd9g0u51x28/OyYf7fIYD9M9528MBls+ElnwPfeZzbEnQgXoLuYOCF8mpsWrl0gmqOySTh10ZWIfhYHRcb5Af0QLlNFZJDX0JvC0P9ETWitYZAZIywjaoLcVlZFi4QGik6aTVLzLxkKbWoSyo/jJySTg36Q+WHP1b3Rf13a7qM7Feeh1fVvtZHckuRtJkvcPFkjbxYSjgeAXF+ZU8fFL97z3n0H+qj7e7jAlY7r9jzX86MHASjaCtRQeRD63htM1RiqBkyVDy0kUc/RAlB2TlECGAxKAEGoiQ7yVkxbgQ4cJkqT9c3zJMuMeVJ1DvP0S79u3cCePrS/T18+/viju6fnlsSYJtVFj+0OM5Ol/n7HOqhrrXiogyr98fA/iIIX+CXQw4Xc77/wBZ43AbNsa0R4thO1Uc3pPKoEQI56pXw8Q3ycr812FETCgLsR9fkyrhua1ts4omgrN0ZNi4eV+flX8lbo1xj/vfSsN8QQZAbQhA5pTYF5oI1MALn0/HDijb2Z6faT0m5WJyZtbj1vTpjqFYbhJ5Fu8z30siyHOM3//B++H6krcvmSrrtcks5XV5/kKghNP+xgu4YKZt4M0rIrBzMHucOmLSzXDALHWhWSJms5PkDUssg0uK+/H7t3xt/g5fXGHj6//b5Uei3C5uiRYxiuEVJAuBrPZRUBEtoC0Inm9qFrhs5H1gKzxIP09ug56DWSJt5oFKDB5eUnfmglkVr39idkATQtp9hi6LPJAIhKbQZAPazIpgU2Jb8lIltJ1pjvSfHuRlkzKspaZcHaizyUx4p2B7M30/TktD+armVRgz9hPZdS4KveSnQ4Qttz/NOZRgA/TUjM/A5C+B3XGc9QWYgZIC69NYfQffQCJ3Q8XDv0wtCbogYurujGpiglb6PoH2oSPawTzFeOCCa+SS9GzhIzX5eM53IShtiD6eCplq4seya0HeTDjBzEpH7bQk+UrmwzNNEfXB6gv54V0p+igMHo1dx3pg4maMv2wpYo6e35bMwDgkt5BC7rba0IwdETGXJPC/kD8LoY6/nh8bF/WZW10CSGWY7KamBiltPqmhSZhOMsRBqk2IusOHVsO9JWLLuR1WAcyGyIEnWWYu0OitpdpD1nHK26lLu0P5VX4DFP5cGH9TBHOiSEqMmj+R7AqgRvFg9KGUCY2BO2dYFLJ0zfhy5jHIl+J3fhCw4mSahok0RtW/wn6Yp2RPiPbWmVzQCwCW4hRBdTFE8xwMGIDqSjAiJKORI5RQ/41lv0JpiElZ3gCAtlWa+6CfMhehlzGPWHX2OOpTQisdK9UC6ZHLle6PKGLY76kqdcpAOrLCXTQl6mCvSj1zKH8W+YSkVbr1TKnCKtRq+oqjZSjksbUWR11kaRwukgb+bDCT973nTuwvBfp5RUjkpJNKipIjic+tC76igavlfaMsjexEVrLSavHTB4GP+wBettEnZ/g5/LNW5/MDdnVTicsAv981cJS0+g+wExecs5NVWxeiiumXn+1HRTdQviz+BKWSDMjXgR8VALjdlykDNduBN7fy3CcLgu5jlahz34GelVoGOJakLfnAUj1BftNXIKsbPl+Xb2ifGN5bImKQpRAKkfZM5sJ5i7JpkvZ+Y69Ekj1zPD3OMZjtLgHRMMoYXZGD57eFUXXd5gEUqkdEXVA7pMTHu1m7mSzuaqbNwnFOsW5Z1XOyWjrniIuINerRT1Gvy8v7+5v64q0V8m6iWqopwPewFQpHOzYS+RFfY6lLghYdNtmSVuujQEKi9xU0Be3FQGGTTW2lJtyQVihQjPl6eDrB2cDhIoVXscw8ADGLxPjzQOrG2VGJDEgbV0HDhGQLxDglpFVENhRNU4cItHIJgytqaBLGNreTO9elFyX8KyTUZ7RFZc4NSAlgZYKX5sqKXWl+InshI8eICtx87Pp8wK46lgLaGAtTSZReqG0RYrhZCHdend9jsrVH1113l8zOLrtcbly4GKQg6BxqK7JDBEXK4NVbCc2iryXVtItZyBTk1VKEbeKWOgUFYGbW1aoi4lURZg67nQnOEQIF0W8GOyK+Qm0jJ6pnBzedvHQeti8yMCtM0uVdPc8M24tGq0LclPFWjnn1m+2xelivn9DmI+JXwjSo3Nbd6TU/KqdDUxha46vm9+ppqRdZHyQceueuwzGsL6sRXvAJk70I/VKBpH4NKuIbbGrEIRS5yqUYg9h0MZBancKpziMu4qo8S/wt0czeaKOBZSPRRStiFjU/7d7qaKbifbaKqkqql0zSwMSawIae3aMs93nDJ/+/0fkV4Vet86g+v+oBQ5nZjixVtc21KVVRI9jsY0o35PL1pW2IID5CId2KGy+sLzuwbKjlAJRKK/LlJzYrKv60JR9JXDiz7VPqcs+qpYMUouqrWR4SDeUj2if/nQ+7Fm489Z8EUVMGL1TQu+VMpx52g9J7hXSMVgBF+bjdXL5fnS+1H9BQZHGCDdxlktpfhGp7PyVuEk7CnSVIw945wyyNsyJXExNoQnm4wGyuXQdj++u/eOkO2OPHsWMOL5605mqM7XyIuS9uPrBjYC1bUCdYM0oDD4L47q2atzUcBVZdM38abD92Cz2eNgl4CS0xkaALHOSCMSlQWBFaMm00RTtfnTBa/onSHIqrnMTMplEbo2DKKe92wVg/320cT5m7dHCijaIy55j2jUqipnBIAP7BJlIQ/t88vLvNaEJS27i02UxQ1rwoU7gAFyQnugNWGlrvzjs89Jow2qWAwzGof2OhW1JrofF/o/gOZUKmrObU+OwxnjQDh6LK+cwxnb+pVHwIwq2NaMA03akxdJV2o+Xyo+E/mIgiVKeTIANw+1mN8Y4dBor/S/w2uVDY15fFqzXqtaDmmqbm6o5LWuXSz5aiBGk2PKxtSW2dTWVdaqSW2nZKrlSObsux7ed03s5BYHt+2apYY7eYS+gzgLrzPuaT3Vqk7wDocACzSz5HiRHD3h/xgC9huOZyqlMb9cwh3Tx6mViw+elIU2WXkpzyDP36RIUu6msoBBnGuv548zBkbbyB1YWjndvrBxOjWgTSiNFzfSdVruVr1sl8qdOZ+nNqkUDH4C1nZ9Mp/xV9ozU+Ucm+M4cIpqnf0PnEJaVtLUDOPue95U3I3aNmQj9U/NdsFFKTM/ZMJKSvra0LO4YKIxkvQAa8GES/iMSQZpR2XU2E6abXyVL5PYJYHCQQiMk1bq2kbDZJTajveIQgbRTkpsqyLVf2Th9dEIqpbFUg+2ZgwFbhn8sl443VtmbMBWWEEIUBfdWd9Q4rSnlhI9i1eOJzK661GpsauYQf48ttCuk8y0c7euHWdPoniGJYuPNW03xM7qzKB5QJyXQ5GzIeSHvd7BKd5hyGuWQ3lBp/KFiXNYcEflq+cJqaqNBgSZdN7/bJsznfN0zudW6Drj+xkN05l5cieP3RKp8PGq4HkCqUstCXG8YJq1u8P87Zts8deB3UKePTTGeaJMAMYDd78s/e9QHrwsvv/oux/et6fBj/9z+DhTXgkII9PK3pAVTfYJfNA38QeWTJccxVcHRj/IFzNBTvUnWDpNc5avxcMpZ9K83CkvyOZ+CuIWjmHmGICS7VTlKy9fR/YLfCAwcpvYm3ZrYgP+Lvcuoh8HZOuX+IbicEWJZ5xR0qzE8/eydyF15JA3ReyGoioFYksHV++8cH0mjFr4bAKtXvN9BNqk5BMJmer8VxIylawPJdAG7G8l0FrWhw/iF8t9+4BrekFOvqpLi2DFnJoUAqji/xUgOJYxv+/7qIttIPfRfMWhVCbTcSom2xOXaos0UVkV90wuoAleBbdPzH1mhVMMKf8gvIsy3V/1kVVcH8++BZflunXEO4rluqaOcsguwTDxYJ0HHjPpUJ4jtt95x/3B4GFwcutsuqHlosvJCflNnHXMJHFdeeesjSxX6Vjg9ueRfrXooJgTeWYogBX+qQ0rUvR6oKWv+IJjgj/zPRnbxvcCEdyP1ls36nPG7sqGYFTb/4CzkA1tc3x8/uL7PgetFoMYNNmyke+9/9KvWzewpw/t79OXjz/+6O7peU2s+hTFId70cnQZ7NpOCeyqoGWtgSBs/MgNvsrnscOZjVwab5GgQlRy5WBWi+oDZARC2sJyzSBwLFpMmlV2RJtOh1c0MZuvTOwV/+T4gito6FJbVaUkmzPrVypCssll2ywMQ89lo6kVjwHawfvsXg370LodDR7DV+v+LhAW4e/DLoLtHPBhjIqLYnl4D1veqDU08dKNMIVBgAxWwFYzp7aCWzCLgOHP8cqcRJe+h0mT8Dp6rwmOoOMW/wA= \ No newline at end of file +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 \ No newline at end of file diff --git a/examples/rvc-app/rvc-common/include/rvc-device.h b/examples/rvc-app/rvc-common/include/rvc-device.h index 79d114ab6f1cfa..e77c86aa6a1fb2 100644 --- a/examples/rvc-app/rvc-common/include/rvc-device.h +++ b/examples/rvc-app/rvc-common/include/rvc-device.h @@ -24,6 +24,8 @@ class RvcDevice bool mDocked = false; bool mCharging = false; + uint8_t mStateBeforePause = 0; + public: /** * This class is responsible for initialising all the RVC clusters and manging the interactions between them as required by diff --git a/examples/rvc-app/rvc-common/src/rvc-device.cpp b/examples/rvc-app/rvc-common/src/rvc-device.cpp index 2ee199d158a84a..3e62b5f1e6f701 100644 --- a/examples/rvc-app/rvc-common/src/rvc-device.cpp +++ b/examples/rvc-app/rvc-common/src/rvc-device.cpp @@ -91,28 +91,47 @@ void RvcDevice::HandleRvcCleanChangeToMode(uint8_t newMode, ModeBase::Commands:: void RvcDevice::HandleOpStatePauseCallback(Clusters::OperationalState::GenericOperationalError & err) { + // This method is only called if the device is in a Pause-compatible state, i.e. `Running` or `SeekingCharger`. + mStateBeforePause = mOperationalStateInstance.GetCurrentOperationalState(); auto error = mOperationalStateInstance.SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kPaused)); - if (error == CHIP_NO_ERROR) - { - err.Set(to_underlying(OperationalState::ErrorStateEnum::kNoError)); - } - else - { - err.Set(to_underlying(OperationalState::ErrorStateEnum::kUnableToCompleteOperation)); - } + err.Set((error == CHIP_NO_ERROR) ? to_underlying(OperationalState::ErrorStateEnum::kNoError) + : to_underlying(OperationalState::ErrorStateEnum::kUnableToCompleteOperation)); } void RvcDevice::HandleOpStateResumeCallback(Clusters::OperationalState::GenericOperationalError & err) { - auto error = mOperationalStateInstance.SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kRunning)); - if (error == CHIP_NO_ERROR) + uint8_t targetState = to_underlying(OperationalState::OperationalStateEnum::kRunning); + + switch (mOperationalStateInstance.GetCurrentOperationalState()) { - err.Set(to_underlying(OperationalState::ErrorStateEnum::kNoError)); + case to_underlying(RvcOperationalState::OperationalStateEnum::kCharging): + case to_underlying(RvcOperationalState::OperationalStateEnum::kDocked): { + if (mRunModeInstance.GetCurrentMode() != RvcRunMode::ModeCleaning && + mRunModeInstance.GetCurrentMode() != RvcRunMode::ModeMapping) + { + err.Set(to_underlying(OperationalState::ErrorStateEnum::kCommandInvalidInState)); + return; + } } - else - { - err.Set(to_underlying(OperationalState::ErrorStateEnum::kUnableToCompleteOperation)); + break; + case to_underlying(OperationalState::OperationalStateEnum::kPaused): { + if (mStateBeforePause == to_underlying(RvcOperationalState::OperationalStateEnum::kSeekingCharger)) + { + targetState = to_underlying(RvcOperationalState::OperationalStateEnum::kSeekingCharger); + } } + break; + default: + // This method is only called if the device is in a resume-compatible state, i.e. `Charging`, `Docked` or + // `Paused`. Therefor, we do not expect to ever enter this branch. + err.Set(to_underlying(OperationalState::ErrorStateEnum::kCommandInvalidInState)); + return; + } + + auto error = mOperationalStateInstance.SetOperationalState(targetState); + + err.Set((error == CHIP_NO_ERROR) ? to_underlying(OperationalState::ErrorStateEnum::kNoError) + : to_underlying(OperationalState::ErrorStateEnum::kUnableToCompleteOperation)); } void RvcDevice::HandleChargedMessage() From 342e33824d4d70cf896456d3ae20bb641cc577e3 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Mon, 18 Dec 2023 10:22:47 -0800 Subject: [PATCH 3/8] Implement cluster subscription API (#31057) --- .../PairOnNetworkLongImSubscribeCommand.kt | 86 +- .../generators/kotlin/MatterClusters.jinja | 86 +- src/controller/java/BUILD.gn | 1 + .../cluster/clusters/AccessControlCluster.kt | 669 ++ .../cluster/clusters/AccountLoginCluster.kt | 372 + .../cluster/clusters/ActionsCluster.kt | 560 ++ .../ActivatedCarbonFilterMonitoringCluster.kt | 743 ++ .../AdministratorCommissioningCluster.kt | 553 ++ .../cluster/clusters/AirQualityCluster.kt | 424 + .../clusters/ApplicationBasicCluster.kt | 821 ++ .../clusters/ApplicationLauncherCluster.kt | 510 ++ .../cluster/clusters/AudioOutputCluster.kt | 489 ++ .../clusters/BallastConfigurationCluster.kt | 1199 +++ .../cluster/clusters/BarrierControlCluster.kt | 923 ++ .../clusters/BasicInformationCluster.kt | 1610 ++++ .../clusters/BinaryInputBasicCluster.kt | 857 ++ .../cluster/clusters/BindingCluster.kt | 438 + .../BooleanSensorConfigurationCluster.kt | 597 ++ .../cluster/clusters/BooleanStateCluster.kt | 424 + .../BridgedDeviceBasicInformationCluster.kt | 1273 +++ ...nDioxideConcentrationMeasurementCluster.kt | 1061 +++ ...MonoxideConcentrationMeasurementCluster.kt | 1061 +++ .../cluster/clusters/ChannelCluster.kt | 582 ++ .../cluster/clusters/ColorControlCluster.kt | 3427 +++++++- .../clusters/ContentAppObserverCluster.kt | 372 + .../cluster/clusters/ContentControlCluster.kt | 847 ++ .../clusters/ContentLauncherCluster.kt | 498 ++ .../DemandResponseLoadControlCluster.kt | 848 ++ .../cluster/clusters/DescriptorCluster.kt | 706 ++ .../clusters/DeviceEnergyManagementCluster.kt | 781 ++ .../cluster/clusters/DiagnosticLogsCluster.kt | 372 + .../clusters/DishwasherAlarmCluster.kt | 577 ++ .../cluster/clusters/DishwasherModeCluster.kt | 627 ++ .../cluster/clusters/DoorLockCluster.kt | 2422 +++++- .../ElectricalEnergyMeasurementCluster.kt | 734 ++ .../clusters/ElectricalMeasurementCluster.kt | 7678 ++++++++++++++++- .../cluster/clusters/EnergyEvseCluster.kt | 1941 +++++ .../EthernetNetworkDiagnosticsCluster.kt | 911 ++ .../cluster/clusters/FanControlCluster.kt | 1048 +++ .../cluster/clusters/FaultInjectionCluster.kt | 372 + .../cluster/clusters/FixedLabelCluster.kt | 439 + .../clusters/FlowMeasurementCluster.kt | 624 ++ ...aldehydeConcentrationMeasurementCluster.kt | 1061 +++ .../clusters/GeneralCommissioningCluster.kt | 643 ++ .../clusters/GeneralDiagnosticsCluster.kt | 925 ++ .../clusters/GroupKeyManagementCluster.kt | 608 ++ .../cluster/clusters/GroupsCluster.kt | 423 + .../clusters/HepaFilterMonitoringCluster.kt | 742 ++ .../cluster/clusters/IcdManagementCluster.kt | 832 ++ .../cluster/clusters/IdentifyCluster.kt | 473 + .../clusters/IlluminanceMeasurementCluster.kt | 694 ++ .../cluster/clusters/KeypadInputCluster.kt | 372 + .../clusters/LaundryDryerControlsCluster.kt | 505 ++ .../clusters/LaundryWasherControlsCluster.kt | 640 ++ .../clusters/LaundryWasherModeCluster.kt | 627 ++ .../cluster/clusters/LevelControlCluster.kt | 1220 +++ .../LocalizationConfigurationCluster.kt | 490 ++ .../cluster/clusters/LowPowerCluster.kt | 372 + .../cluster/clusters/MediaInputCluster.kt | 489 ++ .../cluster/clusters/MediaPlaybackCluster.kt | 1120 +++ .../clusters/MicrowaveOvenControlCluster.kt | 638 ++ .../clusters/MicrowaveOvenModeCluster.kt | 492 ++ .../cluster/clusters/ModeSelectCluster.kt | 744 ++ .../clusters/NetworkCommissioningCluster.kt | 1035 +++ ...nDioxideConcentrationMeasurementCluster.kt | 1061 +++ .../clusters/OccupancySensingCluster.kt | 1040 +++ .../cluster/clusters/OnOffCluster.kt | 658 ++ .../OnOffSwitchConfigurationCluster.kt | 473 + .../clusters/OperationalCredentialsCluster.kt | 735 ++ .../clusters/OperationalStateCluster.kt | 757 ++ .../OtaSoftwareUpdateProviderCluster.kt | 372 + .../OtaSoftwareUpdateRequestorCluster.kt | 612 ++ .../OvenCavityOperationalStateCluster.kt | 762 ++ .../cluster/clusters/OvenModeCluster.kt | 627 ++ .../OzoneConcentrationMeasurementCluster.kt | 1061 +++ .../Pm10ConcentrationMeasurementCluster.kt | 1061 +++ .../Pm1ConcentrationMeasurementCluster.kt | 1061 +++ .../Pm25ConcentrationMeasurementCluster.kt | 1061 +++ .../cluster/clusters/PowerSourceCluster.kt | 2330 +++++ .../PowerSourceConfigurationCluster.kt | 438 + .../clusters/PressureMeasurementCluster.kt | 945 ++ .../clusters/ProxyConfigurationCluster.kt | 373 + .../cluster/clusters/ProxyDiscoveryCluster.kt | 373 + .../cluster/clusters/ProxyValidCluster.kt | 373 + .../clusters/PulseWidthModulationCluster.kt | 373 + .../PumpConfigurationAndControlCluster.kt | 1857 ++++ .../RadonConcentrationMeasurementCluster.kt | 1061 +++ .../clusters/RefrigeratorAlarmCluster.kt | 523 ++ ...TemperatureControlledCabinetModeCluster.kt | 634 ++ .../RelativeHumidityMeasurementCluster.kt | 624 ++ .../cluster/clusters/RvcCleanModeCluster.kt | 559 ++ .../clusters/RvcOperationalStateCluster.kt | 759 ++ .../cluster/clusters/RvcRunModeCluster.kt | 559 ++ .../cluster/clusters/SampleMeiCluster.kt | 423 + .../cluster/clusters/ScenesCluster.kt | 834 ++ .../cluster/clusters/SmokeCoAlarmCluster.kt | 1080 +++ .../clusters/SoftwareDiagnosticsCluster.kt | 616 ++ .../cluster/clusters/SwitchCluster.kt | 533 ++ .../clusters/TargetNavigatorCluster.kt | 494 ++ .../clusters/TemperatureControlCluster.kt | 732 ++ .../clusters/TemperatureMeasurementCluster.kt | 624 ++ .../cluster/clusters/ThermostatCluster.kt | 3301 ++++++- ...mostatUserInterfaceConfigurationCluster.kt | 532 ++ .../ThreadNetworkDiagnosticsCluster.kt | 4130 ++++++++- .../clusters/TimeFormatLocalizationCluster.kt | 552 ++ .../clusters/TimeSynchronizationCluster.kt | 1175 +++ .../cluster/clusters/TimerCluster.kt | 523 ++ ...ompoundsConcentrationMeasurementCluster.kt | 1061 +++ .../clusters/UnitLocalizationCluster.kt | 430 + .../cluster/clusters/UnitTestingCluster.kt | 5208 ++++++++++- .../cluster/clusters/UserLabelCluster.kt | 438 + .../ValveConfigurationAndControlCluster.kt | 1017 +++ .../cluster/clusters/WakeOnLanCluster.kt | 487 ++ .../clusters/WiFiNetworkDiagnosticsCluster.kt | 1248 +++ .../cluster/clusters/WindowCoveringCluster.kt | 1722 ++++ .../matter/controller/SubscriptionStates.kt | 130 + 116 files changed, 106024 insertions(+), 96 deletions(-) create mode 100644 src/controller/java/src/matter/controller/SubscriptionStates.kt diff --git a/examples/kotlin-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImSubscribeCommand.kt b/examples/kotlin-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImSubscribeCommand.kt index c2ea79683ec980..85295328bc40a5 100644 --- a/examples/kotlin-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImSubscribeCommand.kt +++ b/examples/kotlin-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImSubscribeCommand.kt @@ -8,6 +8,8 @@ import kotlinx.coroutines.runBlocking import matter.controller.MatterController import matter.controller.SubscribeRequest import matter.controller.SubscriptionState +import matter.controller.UShortSubscriptionState +import matter.controller.cluster.clusters.IdentifyCluster import matter.controller.model.AttributePath import matter.controller.model.EventPath @@ -24,26 +26,6 @@ class PairOnNetworkLongImSubscribeCommand( DiscoveryFilterType.LONG_DISCRIMINATOR ) { override fun runCommand() { - val attributePaths = - listOf( - AttributePath( - endpointId = WILDCARD_ENDPOINT_ID, - clusterId = WILDCARD_CLUSTER_ID, - attributeId = WILDCARD_EVENT_ID, - ) - ) - - val eventPaths = - listOf( - EventPath( - endpointId = WILDCARD_ENDPOINT_ID, - clusterId = WILDCARD_CLUSTER_ID, - eventId = WILDCARD_EVENT_ID - ) - ) - - val subscribeRequest: SubscribeRequest = SubscribeRequest(eventPaths, attributePaths) - currentCommissioner() .pairDevice( getNodeId(), @@ -57,7 +39,11 @@ class PairOnNetworkLongImSubscribeCommand( runBlocking { try { - startSubscription(subscribeRequest) + // Verify Wildcard subscription + startWildcardSubscription() + + // Verify IdentifyTime attribute subscription + subscribeIdentifyTimeAttribute() } catch (ex: Exception) { logger.log(Level.WARNING, "General subscribe failure occurred with error ${ex.message}") setFailure("subscribe failure") @@ -69,8 +55,28 @@ class PairOnNetworkLongImSubscribeCommand( setSuccess() } - private suspend fun startSubscription(request: SubscribeRequest) { - logger.log(Level.INFO, "Starting subscription") + private suspend fun startWildcardSubscription() { + logger.log(Level.INFO, "Starting wildcard subscription") + + val attributePaths = + listOf( + AttributePath( + endpointId = WILDCARD_ENDPOINT_ID, + clusterId = WILDCARD_CLUSTER_ID, + attributeId = WILDCARD_EVENT_ID, + ) + ) + + val eventPaths = + listOf( + EventPath( + endpointId = WILDCARD_ENDPOINT_ID, + clusterId = WILDCARD_CLUSTER_ID, + eventId = WILDCARD_EVENT_ID + ) + ) + + val request: SubscribeRequest = SubscribeRequest(eventPaths, attributePaths) currentCommissioner() .subscribe(request) @@ -92,7 +98,39 @@ class PairOnNetworkLongImSubscribeCommand( ) } is SubscriptionState.SubscriptionEstablished -> { - logger.log(Level.INFO, "Subscription is established") + logger.log(Level.INFO, "Wildcard Subscription is established") + } + else -> { + logger.log(Level.SEVERE, "Unexpected subscription state: $subscriptionState") + } + } + } + } + + private suspend fun subscribeIdentifyTimeAttribute() { + logger.log(Level.INFO, "Subscribe IdentifyTime attribute") + + val identifyCluster = IdentifyCluster(controller = currentCommissioner(), endpointId = 0u) + + identifyCluster + .subscribeIdentifyTimeAttribute(minInterval = 0, maxInterval = 5) + .takeWhile { subscriptionState -> + // Keep collecting as long as it's not SubscriptionEstablished + subscriptionState !is UShortSubscriptionState.SubscriptionEstablished + } + .collect { subscriptionState -> + when (subscriptionState) { + is UShortSubscriptionState.Success -> { + logger.log(Level.INFO, "Received IdentifyTime Update: ${subscriptionState.value}") + } + is UShortSubscriptionState.Error -> { + logger.log( + Level.WARNING, + "Received SubscriptionErrorNotification with terminationCause: ${subscriptionState.exception}" + ) + } + is UShortSubscriptionState.SubscriptionEstablished -> { + logger.log(Level.INFO, "IdentifyTime Subscription is established") } else -> { logger.log(Level.SEVERE, "Unexpected subscription state: $subscriptionState") diff --git a/scripts/py_matter_idl/matter_idl/generators/kotlin/MatterClusters.jinja b/scripts/py_matter_idl/matter_idl/generators/kotlin/MatterClusters.jinja index 8b9a1a2a1193f7..1f1dffb8fa7888 100644 --- a/scripts/py_matter_idl/matter_idl/generators/kotlin/MatterClusters.jinja +++ b/scripts/py_matter_idl/matter_idl/generators/kotlin/MatterClusters.jinja @@ -126,6 +126,8 @@ package matter.controller.cluster.clusters import java.util.logging.Level import java.util.logging.Logger import java.time.Duration +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadRequest import matter.controller.ReadData @@ -133,6 +135,20 @@ import matter.controller.ReadFailure import matter.controller.ReadResponse import matter.controller.SubscribeRequest import matter.controller.SubscriptionState +import matter.controller.ByteSubscriptionState +import matter.controller.ShortSubscriptionState +import matter.controller.IntSubscriptionState +import matter.controller.LongSubscriptionState +import matter.controller.FloatSubscriptionState +import matter.controller.DoubleSubscriptionState +import matter.controller.CharSubscriptionState +import matter.controller.BooleanSubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UShortSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.ULongSubscriptionState +import matter.controller.StringSubscriptionState +import matter.controller.ByteArraySubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -173,9 +189,20 @@ class {{cluster.name}}Cluster(private val controller: MatterController, private {%- set encodable = attribute.definition | asEncodable(typeLookup) -%} {%- set interfaceName = attribute | javaAttributeCallbackName(typeLookup) -%} {%- if interfaceName not in already_handled_attribute %} +{%- set valueType = encode_value(cluster, encodable, 0) -%} class {{interfaceName}}( - val value: {{encode_value(cluster, encodable, 0)}} + val value: {{valueType}} ) + + sealed class {{interfaceName}}SubscriptionState { + data class Success( + val value: {{valueType}} + ) : {{interfaceName}}SubscriptionState() + + data class Error(val exception: Exception) : {{interfaceName}}SubscriptionState() + + object SubscriptionEstablished : {{interfaceName}}SubscriptionState() + } {% if already_handled_attribute.append(interfaceName) -%} {#- This block does nothing, it only exists to append to already_handled_attribute. -#} {%- endif -%} @@ -387,6 +414,63 @@ class {{cluster.name}}Cluster(private val controller: MatterController, private } } {% endif %} +{%- if attribute.is_subscribable %} +{%- set encodable = attribute.definition | asEncodable(typeLookup) %} +{%- set encodable_was_optional = encodable.is_optional or encodable.is_nullable %} + suspend fun subscribe{{ attribute.definition.name | upfirst }}Attribute( + minInterval: Int, + maxInterval: Int + ): Flow<{{interfaceName}}SubscriptionState> { + val ATTRIBUTE_ID: UInt = {{attribute.definition.code}}u + val attributePaths = listOf( + AttributePath( + endpointId = endpointId, + clusterId = CLUSTER_ID, + attributeId = ATTRIBUTE_ID + ) + ) + + val subscribeRequest: SubscribeRequest = SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit({{interfaceName}}SubscriptionState.Error(Exception("Subscription terminated with error code: ${subscriptionState.terminationCause}"))) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { + "{{ attribute.definition.name | capitalize }} attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: {{encode_value(cluster, encodable, 0)}} = {{decode_tlv(cluster, attribute.definition | asEncodable(typeLookup), "AnonymousTag", 0)}} + + {% if encodable_was_optional-%} + decodedValue?.let { + emit({{interfaceName}}SubscriptionState.Success(it)) + } + {% else -%} + emit({{interfaceName}}SubscriptionState.Success(decodedValue)) + {%- endif %} + } + SubscriptionState.SubscriptionEstablished -> { + emit({{interfaceName}}SubscriptionState.SubscriptionEstablished) + } + } + } + } +{% endif -%} {%- endfor %} companion object { private val logger = Logger.getLogger({{cluster.name}}Cluster::class.java.name) diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index 588535bd823016..1a3b05c73f7ce2 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -371,6 +371,7 @@ kotlin_library("kotlin_matter_controller") { "src/matter/controller/MatterControllerImpl.kt", "src/matter/controller/Messages.kt", "src/matter/controller/OperationalKeyConfig.kt", + "src/matter/controller/SubscriptionStates.kt", "src/matter/controller/model/Paths.kt", "src/matter/controller/model/States.kt", ] diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/AccessControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/AccessControlCluster.kt index 392cc9c9237e64..c42cda3ef21f13 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/AccessControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/AccessControlCluster.kt @@ -20,9 +20,15 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,16 +44,66 @@ class AccessControlCluster( ) { class AclAttribute(val value: List) + sealed class AclAttributeSubscriptionState { + data class Success(val value: List) : + AclAttributeSubscriptionState() + + data class Error(val exception: Exception) : AclAttributeSubscriptionState() + + object SubscriptionEstablished : AclAttributeSubscriptionState() + } + class ExtensionAttribute(val value: List?) + sealed class ExtensionAttributeSubscriptionState { + data class Success(val value: List?) : + ExtensionAttributeSubscriptionState() + + data class Error(val exception: Exception) : ExtensionAttributeSubscriptionState() + + object SubscriptionEstablished : ExtensionAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readAclAttribute(): AclAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -133,6 +189,63 @@ class AccessControlCluster( } } + suspend fun subscribeAclAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AclAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Acl attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(AccessControlClusterAccessControlEntryStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(AclAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AclAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readExtensionAttribute(): ExtensionAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -222,6 +335,72 @@ class AccessControlCluster( } } + suspend fun subscribeExtensionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ExtensionAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Extension attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + AccessControlClusterAccessControlExtensionStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ExtensionAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ExtensionAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSubjectsPerAccessControlEntryAttribute(): UShort { val ATTRIBUTE_ID: UInt = 2u @@ -255,6 +434,58 @@ class AccessControlCluster( return decodedValue } + suspend fun subscribeSubjectsPerAccessControlEntryAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Subjectsperaccesscontrolentry attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTargetsPerAccessControlEntryAttribute(): UShort { val ATTRIBUTE_ID: UInt = 3u @@ -286,6 +517,58 @@ class AccessControlCluster( return decodedValue } + suspend fun subscribeTargetsPerAccessControlEntryAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Targetsperaccesscontrolentry attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAccessControlEntriesPerFabricAttribute(): UShort { val ATTRIBUTE_ID: UInt = 4u @@ -319,6 +602,58 @@ class AccessControlCluster( return decodedValue } + suspend fun subscribeAccessControlEntriesPerFabricAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Accesscontrolentriesperfabric attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -357,6 +692,65 @@ class AccessControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -395,6 +789,65 @@ class AccessControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -433,6 +886,63 @@ class AccessControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -471,6 +981,63 @@ class AccessControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -502,6 +1069,56 @@ class AccessControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -533,6 +1150,58 @@ class AccessControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(AccessControlCluster::class.java.name) const val CLUSTER_ID: UInt = 31u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/AccountLoginCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/AccountLoginCluster.kt index 57c2a50d485a24..d7dcb095c61498 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/AccountLoginCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/AccountLoginCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,12 +47,44 @@ class AccountLoginCluster( class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun getSetupPIN( tempAccountIdentifier: String, timedInvokeTimeout: Duration @@ -185,6 +223,65 @@ class AccountLoginCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -223,6 +320,65 @@ class AccountLoginCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -261,6 +417,63 @@ class AccountLoginCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -299,6 +512,63 @@ class AccountLoginCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -330,6 +600,56 @@ class AccountLoginCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -361,6 +681,58 @@ class AccountLoginCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(AccountLoginCluster::class.java.name) const val CLUSTER_ID: UInt = 1294u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ActionsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ActionsCluster.kt index 3dc76ced6e15de..5f44f5c6a99747 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ActionsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ActionsCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -36,16 +43,66 @@ import matter.tlv.TlvWriter class ActionsCluster(private val controller: MatterController, private val endpointId: UShort) { class ActionListAttribute(val value: List) + sealed class ActionListAttributeSubscriptionState { + data class Success(val value: List) : + ActionListAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActionListAttributeSubscriptionState() + + object SubscriptionEstablished : ActionListAttributeSubscriptionState() + } + class EndpointListsAttribute(val value: List) + sealed class EndpointListsAttributeSubscriptionState { + data class Success(val value: List) : + EndpointListsAttributeSubscriptionState() + + data class Error(val exception: Exception) : EndpointListsAttributeSubscriptionState() + + object SubscriptionEstablished : EndpointListsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun instantAction( actionID: UShort, invokeID: UInt?, @@ -428,6 +485,63 @@ class ActionsCluster(private val controller: MatterController, private val endpo return ActionListAttribute(decodedValue) } + suspend fun subscribeActionListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActionListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Actionlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ActionsClusterActionStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(ActionListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActionListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEndpointListsAttribute(): EndpointListsAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -466,6 +580,63 @@ class ActionsCluster(private val controller: MatterController, private val endpo return EndpointListsAttribute(decodedValue) } + suspend fun subscribeEndpointListsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EndpointListsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Endpointlists attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ActionsClusterEndpointListStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(EndpointListsAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EndpointListsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSetupURLAttribute(): String? { val ATTRIBUTE_ID: UInt = 2u @@ -502,6 +673,61 @@ class ActionsCluster(private val controller: MatterController, private val endpo return decodedValue } + suspend fun subscribeSetupURLAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Setupurl attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -540,6 +766,65 @@ class ActionsCluster(private val controller: MatterController, private val endpo return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -578,6 +863,65 @@ class ActionsCluster(private val controller: MatterController, private val endpo return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -616,6 +960,63 @@ class ActionsCluster(private val controller: MatterController, private val endpo return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -654,6 +1055,63 @@ class ActionsCluster(private val controller: MatterController, private val endpo return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -685,6 +1143,56 @@ class ActionsCluster(private val controller: MatterController, private val endpo return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -716,6 +1224,58 @@ class ActionsCluster(private val controller: MatterController, private val endpo return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ActionsCluster::class.java.name) const val CLUSTER_ID: UInt = 37u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ActivatedCarbonFilterMonitoringCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ActivatedCarbonFilterMonitoringCluster.kt index 4e880bb6392c8d..daa2d6a7bdf0f6 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ActivatedCarbonFilterMonitoringCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ActivatedCarbonFilterMonitoringCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -41,18 +49,68 @@ class ActivatedCarbonFilterMonitoringCluster( ) { class LastChangedTimeAttribute(val value: UInt?) + sealed class LastChangedTimeAttributeSubscriptionState { + data class Success(val value: UInt?) : LastChangedTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : LastChangedTimeAttributeSubscriptionState() + + object SubscriptionEstablished : LastChangedTimeAttributeSubscriptionState() + } + class ReplacementProductListAttribute( val value: List? ) + sealed class ReplacementProductListAttributeSubscriptionState { + data class Success( + val value: List? + ) : ReplacementProductListAttributeSubscriptionState() + + data class Error(val exception: Exception) : ReplacementProductListAttributeSubscriptionState() + + object SubscriptionEstablished : ReplacementProductListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun resetCondition(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -107,6 +165,61 @@ class ActivatedCarbonFilterMonitoringCluster( return decodedValue } + suspend fun subscribeConditionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Condition attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDegradationDirectionAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 1u @@ -143,6 +256,63 @@ class ActivatedCarbonFilterMonitoringCluster( return decodedValue } + suspend fun subscribeDegradationDirectionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Degradationdirection attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readChangeIndicationAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -174,6 +344,58 @@ class ActivatedCarbonFilterMonitoringCluster( return decodedValue } + suspend fun subscribeChangeIndicationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Changeindication attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInPlaceIndicatorAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 3u @@ -210,6 +432,63 @@ class ActivatedCarbonFilterMonitoringCluster( return decodedValue } + suspend fun subscribeInPlaceIndicatorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Inplaceindicator attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLastChangedTimeAttribute(): LastChangedTimeAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -291,6 +570,68 @@ class ActivatedCarbonFilterMonitoringCluster( } } + suspend fun subscribeLastChangedTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LastChangedTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lastchangedtime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LastChangedTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LastChangedTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readReplacementProductListAttribute(): ReplacementProductListAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -338,6 +679,74 @@ class ActivatedCarbonFilterMonitoringCluster( return ReplacementProductListAttribute(decodedValue) } + suspend fun subscribeReplacementProductListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ReplacementProductListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Replacementproductlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + ActivatedCarbonFilterMonitoringClusterReplacementProductStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ReplacementProductListAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ReplacementProductListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -376,6 +785,65 @@ class ActivatedCarbonFilterMonitoringCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -414,6 +882,65 @@ class ActivatedCarbonFilterMonitoringCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -452,6 +979,63 @@ class ActivatedCarbonFilterMonitoringCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -490,6 +1074,63 @@ class ActivatedCarbonFilterMonitoringCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -521,6 +1162,56 @@ class ActivatedCarbonFilterMonitoringCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -552,6 +1243,58 @@ class ActivatedCarbonFilterMonitoringCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ActivatedCarbonFilterMonitoringCluster::class.java.name) const val CLUSTER_ID: UInt = 114u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/AdministratorCommissioningCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/AdministratorCommissioningCluster.kt index ac9877a8c0ff60..4fd1bd91dacbe3 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/AdministratorCommissioningCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/AdministratorCommissioningCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -39,16 +46,64 @@ class AdministratorCommissioningCluster( ) { class AdminFabricIndexAttribute(val value: UByte?) + sealed class AdminFabricIndexAttributeSubscriptionState { + data class Success(val value: UByte?) : AdminFabricIndexAttributeSubscriptionState() + + data class Error(val exception: Exception) : AdminFabricIndexAttributeSubscriptionState() + + object SubscriptionEstablished : AdminFabricIndexAttributeSubscriptionState() + } + class AdminVendorIdAttribute(val value: UShort?) + sealed class AdminVendorIdAttributeSubscriptionState { + data class Success(val value: UShort?) : AdminVendorIdAttributeSubscriptionState() + + data class Error(val exception: Exception) : AdminVendorIdAttributeSubscriptionState() + + object SubscriptionEstablished : AdminVendorIdAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun openCommissioningWindow( commissioningTimeout: UShort, PAKEPasscodeVerifier: ByteArray, @@ -162,6 +217,56 @@ class AdministratorCommissioningCluster( return decodedValue } + suspend fun subscribeWindowStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Windowstatus attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAdminFabricIndexAttribute(): AdminFabricIndexAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -199,6 +304,64 @@ class AdministratorCommissioningCluster( return AdminFabricIndexAttribute(decodedValue) } + suspend fun subscribeAdminFabricIndexAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AdminFabricIndexAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Adminfabricindex attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AdminFabricIndexAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AdminFabricIndexAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAdminVendorIdAttribute(): AdminVendorIdAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -236,6 +399,62 @@ class AdministratorCommissioningCluster( return AdminVendorIdAttribute(decodedValue) } + suspend fun subscribeAdminVendorIdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AdminVendorIdAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Adminvendorid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AdminVendorIdAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AdminVendorIdAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -274,6 +493,65 @@ class AdministratorCommissioningCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -312,6 +590,65 @@ class AdministratorCommissioningCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -350,6 +687,63 @@ class AdministratorCommissioningCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -388,6 +782,63 @@ class AdministratorCommissioningCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -419,6 +870,56 @@ class AdministratorCommissioningCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -450,6 +951,58 @@ class AdministratorCommissioningCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(AdministratorCommissioningCluster::class.java.name) const val CLUSTER_ID: UInt = 60u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/AirQualityCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/AirQualityCluster.kt index c9f7b320e2eafa..b2c558f45df037 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/AirQualityCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/AirQualityCluster.kt @@ -17,11 +17,19 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -30,12 +38,44 @@ import matter.tlv.TlvReader class AirQualityCluster(private val controller: MatterController, private val endpointId: UShort) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readAirQualityAttribute(): UByte { val ATTRIBUTE_ID: UInt = 0u @@ -67,6 +107,56 @@ class AirQualityCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeAirQualityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Airquality attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -105,6 +195,65 @@ class AirQualityCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -143,6 +292,65 @@ class AirQualityCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -181,6 +389,63 @@ class AirQualityCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -219,6 +484,63 @@ class AirQualityCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -250,6 +572,56 @@ class AirQualityCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -281,6 +653,58 @@ class AirQualityCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(AirQualityCluster::class.java.name) const val CLUSTER_ID: UInt = 91u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ApplicationBasicCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ApplicationBasicCluster.kt index 8971387efd222a..ed62272114e72a 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ApplicationBasicCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ApplicationBasicCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,16 +42,65 @@ class ApplicationBasicCluster( ) { class ApplicationAttribute(val value: ApplicationBasicClusterApplicationStruct) + sealed class ApplicationAttributeSubscriptionState { + data class Success(val value: ApplicationBasicClusterApplicationStruct) : + ApplicationAttributeSubscriptionState() + + data class Error(val exception: Exception) : ApplicationAttributeSubscriptionState() + + object SubscriptionEstablished : ApplicationAttributeSubscriptionState() + } + class AllowedVendorListAttribute(val value: List) + sealed class AllowedVendorListAttributeSubscriptionState { + data class Success(val value: List) : AllowedVendorListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AllowedVendorListAttributeSubscriptionState() + + object SubscriptionEstablished : AllowedVendorListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readVendorNameAttribute(): String? { val ATTRIBUTE_ID: UInt = 0u @@ -79,6 +137,61 @@ class ApplicationBasicCluster( return decodedValue } + suspend fun subscribeVendorNameAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Vendorname attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readVendorIDAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1u @@ -115,6 +228,61 @@ class ApplicationBasicCluster( return decodedValue } + suspend fun subscribeVendorIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Vendorid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readApplicationNameAttribute(): String { val ATTRIBUTE_ID: UInt = 2u @@ -146,6 +314,58 @@ class ApplicationBasicCluster( return decodedValue } + suspend fun subscribeApplicationNameAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Applicationname attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductIDAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 3u @@ -182,6 +402,61 @@ class ApplicationBasicCluster( return decodedValue } + suspend fun subscribeProductIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Productid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readApplicationAttribute(): ApplicationAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -214,6 +489,57 @@ class ApplicationBasicCluster( return ApplicationAttribute(decodedValue) } + suspend fun subscribeApplicationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ApplicationAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Application attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ApplicationBasicClusterApplicationStruct = + ApplicationBasicClusterApplicationStruct.fromTlv(AnonymousTag, tlvReader) + + emit(ApplicationAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ApplicationAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStatusAttribute(): UByte { val ATTRIBUTE_ID: UInt = 5u @@ -245,6 +571,56 @@ class ApplicationBasicCluster( return decodedValue } + suspend fun subscribeStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Status attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readApplicationVersionAttribute(): String { val ATTRIBUTE_ID: UInt = 6u @@ -276,6 +652,58 @@ class ApplicationBasicCluster( return decodedValue } + suspend fun subscribeApplicationVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Applicationversion attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAllowedVendorListAttribute(): AllowedVendorListAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -314,6 +742,65 @@ class ApplicationBasicCluster( return AllowedVendorListAttribute(decodedValue) } + suspend fun subscribeAllowedVendorListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AllowedVendorListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Allowedvendorlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUShort(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AllowedVendorListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AllowedVendorListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -352,6 +839,65 @@ class ApplicationBasicCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -390,6 +936,65 @@ class ApplicationBasicCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -428,6 +1033,63 @@ class ApplicationBasicCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -466,6 +1128,63 @@ class ApplicationBasicCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -497,6 +1216,56 @@ class ApplicationBasicCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -528,6 +1297,58 @@ class ApplicationBasicCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ApplicationBasicCluster::class.java.name) const val CLUSTER_ID: UInt = 1293u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ApplicationLauncherCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ApplicationLauncherCluster.kt index 250fd3b0412dbe..7d9f650c50480b 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ApplicationLauncherCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ApplicationLauncherCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,16 +47,65 @@ class ApplicationLauncherCluster( class CatalogListAttribute(val value: List?) + sealed class CatalogListAttributeSubscriptionState { + data class Success(val value: List?) : CatalogListAttributeSubscriptionState() + + data class Error(val exception: Exception) : CatalogListAttributeSubscriptionState() + + object SubscriptionEstablished : CatalogListAttributeSubscriptionState() + } + class CurrentAppAttribute(val value: ApplicationLauncherClusterApplicationEPStruct?) + sealed class CurrentAppAttributeSubscriptionState { + data class Success(val value: ApplicationLauncherClusterApplicationEPStruct?) : + CurrentAppAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentAppAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentAppAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun launchApp( application: ApplicationLauncherClusterApplicationStruct?, data: ByteArray?, @@ -289,6 +344,67 @@ class ApplicationLauncherCluster( return CatalogListAttribute(decodedValue) } + suspend fun subscribeCatalogListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CatalogListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Cataloglist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUShort(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(CatalogListAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CatalogListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentAppAttribute(): CurrentAppAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -330,6 +446,66 @@ class ApplicationLauncherCluster( return CurrentAppAttribute(decodedValue) } + suspend fun subscribeCurrentAppAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentAppAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentapp attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ApplicationLauncherClusterApplicationEPStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + ApplicationLauncherClusterApplicationEPStruct.fromTlv(AnonymousTag, tlvReader) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentAppAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentAppAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -368,6 +544,65 @@ class ApplicationLauncherCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -406,6 +641,65 @@ class ApplicationLauncherCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -444,6 +738,63 @@ class ApplicationLauncherCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -482,6 +833,63 @@ class ApplicationLauncherCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -513,6 +921,56 @@ class ApplicationLauncherCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -544,6 +1002,58 @@ class ApplicationLauncherCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ApplicationLauncherCluster::class.java.name) const val CLUSTER_ID: UInt = 1292u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/AudioOutputCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/AudioOutputCluster.kt index 687f31b086db7c..d5a58d5c07ca1f 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/AudioOutputCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/AudioOutputCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -36,14 +43,55 @@ import matter.tlv.TlvWriter class AudioOutputCluster(private val controller: MatterController, private val endpointId: UShort) { class OutputListAttribute(val value: List) + sealed class OutputListAttributeSubscriptionState { + data class Success(val value: List) : + OutputListAttributeSubscriptionState() + + data class Error(val exception: Exception) : OutputListAttributeSubscriptionState() + + object SubscriptionEstablished : OutputListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun selectOutput(index: UByte, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -127,6 +175,63 @@ class AudioOutputCluster(private val controller: MatterController, private val e return OutputListAttribute(decodedValue) } + suspend fun subscribeOutputListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OutputListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Outputlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(AudioOutputClusterOutputInfoStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(OutputListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(OutputListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentOutputAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -158,6 +263,56 @@ class AudioOutputCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeCurrentOutputAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentoutput attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -196,6 +351,65 @@ class AudioOutputCluster(private val controller: MatterController, private val e return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -234,6 +448,65 @@ class AudioOutputCluster(private val controller: MatterController, private val e return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -272,6 +545,63 @@ class AudioOutputCluster(private val controller: MatterController, private val e return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -310,6 +640,63 @@ class AudioOutputCluster(private val controller: MatterController, private val e return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -341,6 +728,56 @@ class AudioOutputCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -372,6 +809,58 @@ class AudioOutputCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(AudioOutputCluster::class.java.name) const val CLUSTER_ID: UInt = 1291u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BallastConfigurationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BallastConfigurationCluster.kt index cf2a3dc53cea40..a0b361cdbb2400 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BallastConfigurationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BallastConfigurationCluster.kt @@ -20,9 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,22 +46,95 @@ class BallastConfigurationCluster( ) { class IntrinsicBallastFactorAttribute(val value: UByte?) + sealed class IntrinsicBallastFactorAttributeSubscriptionState { + data class Success(val value: UByte?) : IntrinsicBallastFactorAttributeSubscriptionState() + + data class Error(val exception: Exception) : IntrinsicBallastFactorAttributeSubscriptionState() + + object SubscriptionEstablished : IntrinsicBallastFactorAttributeSubscriptionState() + } + class BallastFactorAdjustmentAttribute(val value: UByte?) + sealed class BallastFactorAdjustmentAttributeSubscriptionState { + data class Success(val value: UByte?) : BallastFactorAdjustmentAttributeSubscriptionState() + + data class Error(val exception: Exception) : + BallastFactorAdjustmentAttributeSubscriptionState() + + object SubscriptionEstablished : BallastFactorAdjustmentAttributeSubscriptionState() + } + class LampRatedHoursAttribute(val value: UInt?) + sealed class LampRatedHoursAttributeSubscriptionState { + data class Success(val value: UInt?) : LampRatedHoursAttributeSubscriptionState() + + data class Error(val exception: Exception) : LampRatedHoursAttributeSubscriptionState() + + object SubscriptionEstablished : LampRatedHoursAttributeSubscriptionState() + } + class LampBurnHoursAttribute(val value: UInt?) + sealed class LampBurnHoursAttributeSubscriptionState { + data class Success(val value: UInt?) : LampBurnHoursAttributeSubscriptionState() + + data class Error(val exception: Exception) : LampBurnHoursAttributeSubscriptionState() + + object SubscriptionEstablished : LampBurnHoursAttributeSubscriptionState() + } + class LampBurnHoursTripPointAttribute(val value: UInt?) + sealed class LampBurnHoursTripPointAttributeSubscriptionState { + data class Success(val value: UInt?) : LampBurnHoursTripPointAttributeSubscriptionState() + + data class Error(val exception: Exception) : LampBurnHoursTripPointAttributeSubscriptionState() + + object SubscriptionEstablished : LampBurnHoursTripPointAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readPhysicalMinLevelAttribute(): UByte { val ATTRIBUTE_ID: UInt = 0u @@ -85,6 +166,58 @@ class BallastConfigurationCluster( return decodedValue } + suspend fun subscribePhysicalMinLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Physicalminlevel attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPhysicalMaxLevelAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -116,6 +249,58 @@ class BallastConfigurationCluster( return decodedValue } + suspend fun subscribePhysicalMaxLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Physicalmaxlevel attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBallastStatusAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -152,6 +337,61 @@ class BallastConfigurationCluster( return decodedValue } + suspend fun subscribeBallastStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Ballaststatus attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinLevelAttribute(): UByte { val ATTRIBUTE_ID: UInt = 16u @@ -223,6 +463,56 @@ class BallastConfigurationCluster( } } + suspend fun subscribeMinLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Minlevel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxLevelAttribute(): UByte { val ATTRIBUTE_ID: UInt = 17u @@ -294,6 +584,56 @@ class BallastConfigurationCluster( } } + suspend fun subscribeMaxLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxlevel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readIntrinsicBallastFactorAttribute(): IntrinsicBallastFactorAttribute { val ATTRIBUTE_ID: UInt = 20u @@ -378,6 +718,68 @@ class BallastConfigurationCluster( } } + suspend fun subscribeIntrinsicBallastFactorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + IntrinsicBallastFactorAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Intrinsicballastfactor attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(IntrinsicBallastFactorAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(IntrinsicBallastFactorAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBallastFactorAdjustmentAttribute(): BallastFactorAdjustmentAttribute { val ATTRIBUTE_ID: UInt = 21u @@ -462,6 +864,68 @@ class BallastConfigurationCluster( } } + suspend fun subscribeBallastFactorAdjustmentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 21u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BallastFactorAdjustmentAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Ballastfactoradjustment attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BallastFactorAdjustmentAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BallastFactorAdjustmentAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLampQuantityAttribute(): UByte { val ATTRIBUTE_ID: UInt = 32u @@ -493,6 +957,56 @@ class BallastConfigurationCluster( return decodedValue } + suspend fun subscribeLampQuantityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 32u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Lampquantity attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLampTypeAttribute(): String? { val ATTRIBUTE_ID: UInt = 48u @@ -569,6 +1083,61 @@ class BallastConfigurationCluster( } } + suspend fun subscribeLampTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 48u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Lamptype attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLampManufacturerAttribute(): String? { val ATTRIBUTE_ID: UInt = 49u @@ -645,6 +1214,63 @@ class BallastConfigurationCluster( } } + suspend fun subscribeLampManufacturerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 49u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lampmanufacturer attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLampRatedHoursAttribute(): LampRatedHoursAttribute { val ATTRIBUTE_ID: UInt = 50u @@ -726,6 +1352,68 @@ class BallastConfigurationCluster( } } + suspend fun subscribeLampRatedHoursAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 50u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LampRatedHoursAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lampratedhours attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LampRatedHoursAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LampRatedHoursAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLampBurnHoursAttribute(): LampBurnHoursAttribute { val ATTRIBUTE_ID: UInt = 51u @@ -807,6 +1495,66 @@ class BallastConfigurationCluster( } } + suspend fun subscribeLampBurnHoursAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 51u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LampBurnHoursAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Lampburnhours attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LampBurnHoursAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LampBurnHoursAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLampAlarmModeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 52u @@ -883,6 +1631,61 @@ class BallastConfigurationCluster( } } + suspend fun subscribeLampAlarmModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 52u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Lampalarmmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLampBurnHoursTripPointAttribute(): LampBurnHoursTripPointAttribute { val ATTRIBUTE_ID: UInt = 53u @@ -967,6 +1770,68 @@ class BallastConfigurationCluster( } } + suspend fun subscribeLampBurnHoursTripPointAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 53u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LampBurnHoursTripPointAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lampburnhourstrippoint attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LampBurnHoursTripPointAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LampBurnHoursTripPointAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1005,6 +1870,65 @@ class BallastConfigurationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1043,6 +1967,65 @@ class BallastConfigurationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1081,6 +2064,63 @@ class BallastConfigurationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1119,6 +2159,63 @@ class BallastConfigurationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1150,6 +2247,56 @@ class BallastConfigurationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1181,6 +2328,58 @@ class BallastConfigurationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(BallastConfigurationCluster::class.java.name) const val CLUSTER_ID: UInt = 769u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BarrierControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BarrierControlCluster.kt index f66abbd74093ad..baddce34338c61 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BarrierControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BarrierControlCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -42,12 +49,44 @@ class BarrierControlCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun barrierControlGoToPercent(percentOpen: UByte, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -118,6 +157,58 @@ class BarrierControlCluster( return decodedValue } + suspend fun subscribeBarrierMovingStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barriermovingstate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBarrierSafetyStatusAttribute(): UShort { val ATTRIBUTE_ID: UInt = 2u @@ -149,6 +240,58 @@ class BarrierControlCluster( return decodedValue } + suspend fun subscribeBarrierSafetyStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barriersafetystatus attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBarrierCapabilitiesAttribute(): UByte { val ATTRIBUTE_ID: UInt = 3u @@ -180,6 +323,58 @@ class BarrierControlCluster( return decodedValue } + suspend fun subscribeBarrierCapabilitiesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barriercapabilities attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBarrierOpenEventsAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 4u @@ -256,6 +451,63 @@ class BarrierControlCluster( } } + suspend fun subscribeBarrierOpenEventsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barrieropenevents attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBarrierCloseEventsAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 5u @@ -332,6 +584,63 @@ class BarrierControlCluster( } } + suspend fun subscribeBarrierCloseEventsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barriercloseevents attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBarrierCommandOpenEventsAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 6u @@ -411,6 +720,63 @@ class BarrierControlCluster( } } + suspend fun subscribeBarrierCommandOpenEventsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barriercommandopenevents attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBarrierCommandCloseEventsAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 7u @@ -490,6 +856,63 @@ class BarrierControlCluster( } } + suspend fun subscribeBarrierCommandCloseEventsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barriercommandcloseevents attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBarrierOpenPeriodAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 8u @@ -566,6 +989,63 @@ class BarrierControlCluster( } } + suspend fun subscribeBarrierOpenPeriodAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barrieropenperiod attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBarrierClosePeriodAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 9u @@ -642,6 +1122,63 @@ class BarrierControlCluster( } } + suspend fun subscribeBarrierClosePeriodAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barriercloseperiod attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBarrierPositionAttribute(): UByte { val ATTRIBUTE_ID: UInt = 10u @@ -673,6 +1210,58 @@ class BarrierControlCluster( return decodedValue } + suspend fun subscribeBarrierPositionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Barrierposition attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -711,6 +1300,65 @@ class BarrierControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -749,6 +1397,65 @@ class BarrierControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -787,6 +1494,63 @@ class BarrierControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -825,6 +1589,63 @@ class BarrierControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -856,6 +1677,56 @@ class BarrierControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -887,6 +1758,58 @@ class BarrierControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(BarrierControlCluster::class.java.name) const val CLUSTER_ID: UInt = 259u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BasicInformationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BasicInformationCluster.kt index d11d31f21cb09d..0a669f0fddd221 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BasicInformationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BasicInformationCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -41,16 +49,66 @@ class BasicInformationCluster( ) { class CapabilityMinimaAttribute(val value: BasicInformationClusterCapabilityMinimaStruct) + sealed class CapabilityMinimaAttributeSubscriptionState { + data class Success(val value: BasicInformationClusterCapabilityMinimaStruct) : + CapabilityMinimaAttributeSubscriptionState() + + data class Error(val exception: Exception) : CapabilityMinimaAttributeSubscriptionState() + + object SubscriptionEstablished : CapabilityMinimaAttributeSubscriptionState() + } + class ProductAppearanceAttribute(val value: BasicInformationClusterProductAppearanceStruct?) + sealed class ProductAppearanceAttributeSubscriptionState { + data class Success(val value: BasicInformationClusterProductAppearanceStruct?) : + ProductAppearanceAttributeSubscriptionState() + + data class Error(val exception: Exception) : ProductAppearanceAttributeSubscriptionState() + + object SubscriptionEstablished : ProductAppearanceAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun mfgSpecificPing(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -100,6 +158,58 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeDataModelRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Datamodelrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readVendorNameAttribute(): String { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +241,56 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeVendorNameAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Vendorname attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readVendorIDAttribute(): UShort { val ATTRIBUTE_ID: UInt = 2u @@ -162,6 +322,56 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeVendorIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Vendorid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductNameAttribute(): String { val ATTRIBUTE_ID: UInt = 3u @@ -193,6 +403,56 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeProductNameAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Productname attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductIDAttribute(): UShort { val ATTRIBUTE_ID: UInt = 4u @@ -224,6 +484,56 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeProductIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Productid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNodeLabelAttribute(): String { val ATTRIBUTE_ID: UInt = 5u @@ -295,6 +605,56 @@ class BasicInformationCluster( } } + suspend fun subscribeNodeLabelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Nodelabel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLocationAttribute(): String { val ATTRIBUTE_ID: UInt = 6u @@ -366,6 +726,56 @@ class BasicInformationCluster( } } + suspend fun subscribeLocationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Location attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readHardwareVersionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 7u @@ -397,6 +807,58 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeHardwareVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Hardwareversion attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readHardwareVersionStringAttribute(): String { val ATTRIBUTE_ID: UInt = 8u @@ -428,6 +890,58 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeHardwareVersionStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Hardwareversionstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSoftwareVersionAttribute(): UInt { val ATTRIBUTE_ID: UInt = 9u @@ -459,6 +973,58 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeSoftwareVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Softwareversion attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSoftwareVersionStringAttribute(): String { val ATTRIBUTE_ID: UInt = 10u @@ -490,6 +1056,58 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeSoftwareVersionStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Softwareversionstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readManufacturingDateAttribute(): String? { val ATTRIBUTE_ID: UInt = 11u @@ -526,6 +1144,63 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeManufacturingDateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Manufacturingdate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPartNumberAttribute(): String? { val ATTRIBUTE_ID: UInt = 12u @@ -562,6 +1237,61 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribePartNumberAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Partnumber attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductURLAttribute(): String? { val ATTRIBUTE_ID: UInt = 13u @@ -598,6 +1328,61 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeProductURLAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 13u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Producturl attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductLabelAttribute(): String? { val ATTRIBUTE_ID: UInt = 14u @@ -634,6 +1419,61 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeProductLabelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 14u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Productlabel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSerialNumberAttribute(): String? { val ATTRIBUTE_ID: UInt = 15u @@ -670,6 +1510,61 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeSerialNumberAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 15u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Serialnumber attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLocalConfigDisabledAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 16u @@ -749,6 +1644,63 @@ class BasicInformationCluster( } } + suspend fun subscribeLocalConfigDisabledAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Localconfigdisabled attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readReachableAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 17u @@ -785,6 +1737,61 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeReachableAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Reachable attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUniqueIDAttribute(): String? { val ATTRIBUTE_ID: UInt = 18u @@ -821,6 +1828,61 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeUniqueIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uniqueid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCapabilityMinimaAttribute(): CapabilityMinimaAttribute { val ATTRIBUTE_ID: UInt = 19u @@ -853,6 +1915,59 @@ class BasicInformationCluster( return CapabilityMinimaAttribute(decodedValue) } + suspend fun subscribeCapabilityMinimaAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CapabilityMinimaAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Capabilityminima attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: BasicInformationClusterCapabilityMinimaStruct = + BasicInformationClusterCapabilityMinimaStruct.fromTlv(AnonymousTag, tlvReader) + + emit(CapabilityMinimaAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(CapabilityMinimaAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductAppearanceAttribute(): ProductAppearanceAttribute { val ATTRIBUTE_ID: UInt = 20u @@ -889,6 +2004,63 @@ class BasicInformationCluster( return ProductAppearanceAttribute(decodedValue) } + suspend fun subscribeProductAppearanceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ProductAppearanceAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Productappearance attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: BasicInformationClusterProductAppearanceStruct? = + if (tlvReader.isNextTag(AnonymousTag)) { + BasicInformationClusterProductAppearanceStruct.fromTlv(AnonymousTag, tlvReader) + } else { + null + } + + decodedValue?.let { emit(ProductAppearanceAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ProductAppearanceAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSpecificationVersionAttribute(): UInt { val ATTRIBUTE_ID: UInt = 21u @@ -920,6 +2092,58 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeSpecificationVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 21u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Specificationversion attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxPathsPerInvokeAttribute(): UShort { val ATTRIBUTE_ID: UInt = 22u @@ -951,6 +2175,58 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeMaxPathsPerInvokeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 22u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxpathsperinvoke attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -989,6 +2265,65 @@ class BasicInformationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1027,6 +2362,65 @@ class BasicInformationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1065,6 +2459,63 @@ class BasicInformationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1103,6 +2554,63 @@ class BasicInformationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1134,6 +2642,56 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1165,6 +2723,58 @@ class BasicInformationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(BasicInformationCluster::class.java.name) const val CLUSTER_ID: UInt = 40u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BinaryInputBasicCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BinaryInputBasicCluster.kt index 0493925c50e51e..89769881291daf 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BinaryInputBasicCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BinaryInputBasicCluster.kt @@ -20,9 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,12 +47,44 @@ class BinaryInputBasicCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readActiveTextAttribute(): String? { val ATTRIBUTE_ID: UInt = 4u @@ -120,6 +161,61 @@ class BinaryInputBasicCluster( } } + suspend fun subscribeActiveTextAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Activetext attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDescriptionAttribute(): String? { val ATTRIBUTE_ID: UInt = 28u @@ -196,6 +292,61 @@ class BinaryInputBasicCluster( } } + suspend fun subscribeDescriptionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 28u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Description attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInactiveTextAttribute(): String? { val ATTRIBUTE_ID: UInt = 46u @@ -272,6 +423,61 @@ class BinaryInputBasicCluster( } } + suspend fun subscribeInactiveTextAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 46u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Inactivetext attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOutOfServiceAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 81u @@ -343,6 +549,56 @@ class BinaryInputBasicCluster( } } + suspend fun subscribeOutOfServiceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 81u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Outofservice attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPolarityAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 84u @@ -379,6 +635,61 @@ class BinaryInputBasicCluster( return decodedValue } + suspend fun subscribePolarityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 84u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Polarity attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPresentValueAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 85u @@ -450,6 +761,56 @@ class BinaryInputBasicCluster( } } + suspend fun subscribePresentValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 85u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Presentvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readReliabilityAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 103u @@ -526,6 +887,61 @@ class BinaryInputBasicCluster( } } + suspend fun subscribeReliabilityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 103u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Reliability attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStatusFlagsAttribute(): UByte { val ATTRIBUTE_ID: UInt = 111u @@ -557,6 +973,56 @@ class BinaryInputBasicCluster( return decodedValue } + suspend fun subscribeStatusFlagsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 111u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Statusflags attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readApplicationTypeAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 256u @@ -593,6 +1059,63 @@ class BinaryInputBasicCluster( return decodedValue } + suspend fun subscribeApplicationTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 256u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Applicationtype attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -631,6 +1154,65 @@ class BinaryInputBasicCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -669,6 +1251,65 @@ class BinaryInputBasicCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -707,6 +1348,63 @@ class BinaryInputBasicCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -745,6 +1443,63 @@ class BinaryInputBasicCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -776,6 +1531,56 @@ class BinaryInputBasicCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -807,6 +1612,58 @@ class BinaryInputBasicCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(BinaryInputBasicCluster::class.java.name) const val CLUSTER_ID: UInt = 15u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BindingCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BindingCluster.kt index fe716ecd52499b..a5cb5193c9c37d 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BindingCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BindingCluster.kt @@ -20,9 +20,15 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -35,14 +41,55 @@ import matter.tlv.TlvWriter class BindingCluster(private val controller: MatterController, private val endpointId: UShort) { class BindingAttribute(val value: List) + sealed class BindingAttributeSubscriptionState { + data class Success(val value: List) : + BindingAttributeSubscriptionState() + + data class Error(val exception: Exception) : BindingAttributeSubscriptionState() + + object SubscriptionEstablished : BindingAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readBindingAttribute(): BindingAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -128,6 +175,63 @@ class BindingCluster(private val controller: MatterController, private val endpo } } + suspend fun subscribeBindingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BindingAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Binding attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(BindingClusterTargetStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(BindingAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BindingAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -166,6 +270,65 @@ class BindingCluster(private val controller: MatterController, private val endpo return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -204,6 +367,65 @@ class BindingCluster(private val controller: MatterController, private val endpo return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -242,6 +464,63 @@ class BindingCluster(private val controller: MatterController, private val endpo return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -280,6 +559,63 @@ class BindingCluster(private val controller: MatterController, private val endpo return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -311,6 +647,56 @@ class BindingCluster(private val controller: MatterController, private val endpo return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -342,6 +728,58 @@ class BindingCluster(private val controller: MatterController, private val endpo return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(BindingCluster::class.java.name) const val CLUSTER_ID: UInt = 30u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanSensorConfigurationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanSensorConfigurationCluster.kt index ca91dc5f0d62f3..510d0c3e4f3db4 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanSensorConfigurationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanSensorConfigurationCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -42,12 +49,44 @@ class BooleanSensorConfigurationCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun suppressRequest(alarmsToSuppress: UByte, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -145,6 +184,63 @@ class BooleanSensorConfigurationCluster( } } + suspend fun subscribeSensitivityLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Sensitivitylevel attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAlarmsActiveAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 1u @@ -181,6 +277,61 @@ class BooleanSensorConfigurationCluster( return decodedValue } + suspend fun subscribeAlarmsActiveAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Alarmsactive attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAlarmsSuppressedAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -217,6 +368,63 @@ class BooleanSensorConfigurationCluster( return decodedValue } + suspend fun subscribeAlarmsSuppressedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Alarmssuppressed attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAlarmsEnabledAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 3u @@ -293,6 +501,61 @@ class BooleanSensorConfigurationCluster( } } + suspend fun subscribeAlarmsEnabledAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Alarmsenabled attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -331,6 +594,65 @@ class BooleanSensorConfigurationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -369,6 +691,65 @@ class BooleanSensorConfigurationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -407,6 +788,63 @@ class BooleanSensorConfigurationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -445,6 +883,63 @@ class BooleanSensorConfigurationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -476,6 +971,56 @@ class BooleanSensorConfigurationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -507,6 +1052,58 @@ class BooleanSensorConfigurationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(BooleanSensorConfigurationCluster::class.java.name) const val CLUSTER_ID: UInt = 128u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanStateCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanStateCluster.kt index 19e1e5207f5d29..7530f3afc9c7cb 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanStateCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanStateCluster.kt @@ -17,11 +17,19 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,12 +41,44 @@ class BooleanStateCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readStateValueAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 0u @@ -70,6 +110,56 @@ class BooleanStateCluster( return decodedValue } + suspend fun subscribeStateValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Statevalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -108,6 +198,65 @@ class BooleanStateCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -146,6 +295,65 @@ class BooleanStateCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -184,6 +392,63 @@ class BooleanStateCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -222,6 +487,63 @@ class BooleanStateCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -253,6 +575,56 @@ class BooleanStateCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -284,6 +656,58 @@ class BooleanStateCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(BooleanStateCluster::class.java.name) const val CLUSTER_ID: UInt = 69u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BridgedDeviceBasicInformationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BridgedDeviceBasicInformationCluster.kt index 756682b508f4f4..e867b53a3b8e24 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BridgedDeviceBasicInformationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BridgedDeviceBasicInformationCluster.kt @@ -20,9 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -40,14 +48,55 @@ class BridgedDeviceBasicInformationCluster( val value: BridgedDeviceBasicInformationClusterProductAppearanceStruct? ) + sealed class ProductAppearanceAttributeSubscriptionState { + data class Success(val value: BridgedDeviceBasicInformationClusterProductAppearanceStruct?) : + ProductAppearanceAttributeSubscriptionState() + + data class Error(val exception: Exception) : ProductAppearanceAttributeSubscriptionState() + + object SubscriptionEstablished : ProductAppearanceAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readVendorNameAttribute(): String? { val ATTRIBUTE_ID: UInt = 1u @@ -84,6 +133,61 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeVendorNameAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Vendorname attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readVendorIDAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2u @@ -120,6 +224,61 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeVendorIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Vendorid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductNameAttribute(): String? { val ATTRIBUTE_ID: UInt = 3u @@ -156,6 +315,61 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeProductNameAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Productname attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNodeLabelAttribute(): String? { val ATTRIBUTE_ID: UInt = 5u @@ -232,6 +446,61 @@ class BridgedDeviceBasicInformationCluster( } } + suspend fun subscribeNodeLabelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Nodelabel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readHardwareVersionAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 7u @@ -268,6 +537,63 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeHardwareVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Hardwareversion attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readHardwareVersionStringAttribute(): String? { val ATTRIBUTE_ID: UInt = 8u @@ -304,6 +630,63 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeHardwareVersionStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Hardwareversionstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSoftwareVersionAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 9u @@ -340,6 +723,63 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeSoftwareVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Softwareversion attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSoftwareVersionStringAttribute(): String? { val ATTRIBUTE_ID: UInt = 10u @@ -376,6 +816,63 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeSoftwareVersionStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Softwareversionstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readManufacturingDateAttribute(): String? { val ATTRIBUTE_ID: UInt = 11u @@ -412,6 +909,63 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeManufacturingDateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Manufacturingdate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPartNumberAttribute(): String? { val ATTRIBUTE_ID: UInt = 12u @@ -448,6 +1002,61 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribePartNumberAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Partnumber attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductURLAttribute(): String? { val ATTRIBUTE_ID: UInt = 13u @@ -484,6 +1093,61 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeProductURLAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 13u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Producturl attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductLabelAttribute(): String? { val ATTRIBUTE_ID: UInt = 14u @@ -520,6 +1184,61 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeProductLabelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 14u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Productlabel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSerialNumberAttribute(): String? { val ATTRIBUTE_ID: UInt = 15u @@ -556,6 +1275,61 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeSerialNumberAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 15u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Serialnumber attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readReachableAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 17u @@ -587,6 +1361,56 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeReachableAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Reachable attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUniqueIDAttribute(): String? { val ATTRIBUTE_ID: UInt = 18u @@ -623,6 +1447,61 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeUniqueIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uniqueid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readProductAppearanceAttribute(): ProductAppearanceAttribute { val ATTRIBUTE_ID: UInt = 20u @@ -659,6 +1538,66 @@ class BridgedDeviceBasicInformationCluster( return ProductAppearanceAttribute(decodedValue) } + suspend fun subscribeProductAppearanceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ProductAppearanceAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Productappearance attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: BridgedDeviceBasicInformationClusterProductAppearanceStruct? = + if (tlvReader.isNextTag(AnonymousTag)) { + BridgedDeviceBasicInformationClusterProductAppearanceStruct.fromTlv( + AnonymousTag, + tlvReader + ) + } else { + null + } + + decodedValue?.let { emit(ProductAppearanceAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ProductAppearanceAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -697,6 +1636,65 @@ class BridgedDeviceBasicInformationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -735,6 +1733,65 @@ class BridgedDeviceBasicInformationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -773,6 +1830,63 @@ class BridgedDeviceBasicInformationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -811,6 +1925,63 @@ class BridgedDeviceBasicInformationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -842,6 +2013,56 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -873,6 +2094,58 @@ class BridgedDeviceBasicInformationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(BridgedDeviceBasicInformationCluster::class.java.name) const val CLUSTER_ID: UInt = 57u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonDioxideConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonDioxideConcentrationMeasurementCluster.kt index d76d7309276360..d2f974c4550a9b 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonDioxideConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonDioxideConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class CarbonDioxideConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class CarbonDioxideConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class CarbonDioxideConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class CarbonDioxideConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class CarbonDioxideConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class CarbonDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class CarbonDioxideConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class CarbonDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class CarbonDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class CarbonDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class CarbonDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class CarbonDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class CarbonDioxideConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class CarbonDioxideConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class CarbonDioxideConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class CarbonDioxideConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class CarbonDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class CarbonDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(CarbonDioxideConcentrationMeasurementCluster::class.java.name) diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonMonoxideConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonMonoxideConcentrationMeasurementCluster.kt index e52a35e6e5cc80..93341731a25b70 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonMonoxideConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonMonoxideConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class CarbonMonoxideConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class CarbonMonoxideConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class CarbonMonoxideConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class CarbonMonoxideConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class CarbonMonoxideConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class CarbonMonoxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class CarbonMonoxideConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class CarbonMonoxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class CarbonMonoxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class CarbonMonoxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class CarbonMonoxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class CarbonMonoxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class CarbonMonoxideConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class CarbonMonoxideConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class CarbonMonoxideConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class CarbonMonoxideConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class CarbonMonoxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class CarbonMonoxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(CarbonMonoxideConcentrationMeasurementCluster::class.java.name) diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ChannelCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ChannelCluster.kt index 8de317d01f0f94..7825944363b1aa 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ChannelCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ChannelCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -43,18 +49,77 @@ class ChannelCluster(private val controller: MatterController, private val endpo class ChannelListAttribute(val value: List?) + sealed class ChannelListAttributeSubscriptionState { + data class Success(val value: List?) : + ChannelListAttributeSubscriptionState() + + data class Error(val exception: Exception) : ChannelListAttributeSubscriptionState() + + object SubscriptionEstablished : ChannelListAttributeSubscriptionState() + } + class LineupAttribute(val value: ChannelClusterLineupInfoStruct?) + sealed class LineupAttributeSubscriptionState { + data class Success(val value: ChannelClusterLineupInfoStruct?) : + LineupAttributeSubscriptionState() + + data class Error(val exception: Exception) : LineupAttributeSubscriptionState() + + object SubscriptionEstablished : LineupAttributeSubscriptionState() + } + class CurrentChannelAttribute(val value: ChannelClusterChannelInfoStruct?) + sealed class CurrentChannelAttributeSubscriptionState { + data class Success(val value: ChannelClusterChannelInfoStruct?) : + CurrentChannelAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentChannelAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentChannelAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun changeChannel( match: String, timedInvokeTimeout: Duration? = null @@ -391,6 +456,67 @@ class ChannelCluster(private val controller: MatterController, private val endpo return ChannelListAttribute(decodedValue) } + suspend fun subscribeChannelListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ChannelListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Channellist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ChannelClusterChannelInfoStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ChannelListAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ChannelListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLineupAttribute(): LineupAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -432,6 +558,66 @@ class ChannelCluster(private val controller: MatterController, private val endpo return LineupAttribute(decodedValue) } + suspend fun subscribeLineupAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LineupAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Lineup attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ChannelClusterLineupInfoStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + ChannelClusterLineupInfoStruct.fromTlv(AnonymousTag, tlvReader) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LineupAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LineupAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentChannelAttribute(): CurrentChannelAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -473,6 +659,68 @@ class ChannelCluster(private val controller: MatterController, private val endpo return CurrentChannelAttribute(decodedValue) } + suspend fun subscribeCurrentChannelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentChannelAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentchannel attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ChannelClusterChannelInfoStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + ChannelClusterChannelInfoStruct.fromTlv(AnonymousTag, tlvReader) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentChannelAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentChannelAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -511,6 +759,65 @@ class ChannelCluster(private val controller: MatterController, private val endpo return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -549,6 +856,65 @@ class ChannelCluster(private val controller: MatterController, private val endpo return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -587,6 +953,63 @@ class ChannelCluster(private val controller: MatterController, private val endpo return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -625,6 +1048,63 @@ class ChannelCluster(private val controller: MatterController, private val endpo return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -656,6 +1136,56 @@ class ChannelCluster(private val controller: MatterController, private val endpo return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -687,6 +1217,58 @@ class ChannelCluster(private val controller: MatterController, private val endpo return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ChannelCluster::class.java.name) const val CLUSTER_ID: UInt = 1284u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ColorControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ColorControlCluster.kt index 73001c338d7a6d..29633f95e9ab20 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ColorControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ColorControlCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -42,34 +50,156 @@ class ColorControlCluster( ) { class NumberOfPrimariesAttribute(val value: UByte?) + sealed class NumberOfPrimariesAttributeSubscriptionState { + data class Success(val value: UByte?) : NumberOfPrimariesAttributeSubscriptionState() + + data class Error(val exception: Exception) : NumberOfPrimariesAttributeSubscriptionState() + + object SubscriptionEstablished : NumberOfPrimariesAttributeSubscriptionState() + } + class Primary1IntensityAttribute(val value: UByte?) + sealed class Primary1IntensityAttributeSubscriptionState { + data class Success(val value: UByte?) : Primary1IntensityAttributeSubscriptionState() + + data class Error(val exception: Exception) : Primary1IntensityAttributeSubscriptionState() + + object SubscriptionEstablished : Primary1IntensityAttributeSubscriptionState() + } + class Primary2IntensityAttribute(val value: UByte?) + sealed class Primary2IntensityAttributeSubscriptionState { + data class Success(val value: UByte?) : Primary2IntensityAttributeSubscriptionState() + + data class Error(val exception: Exception) : Primary2IntensityAttributeSubscriptionState() + + object SubscriptionEstablished : Primary2IntensityAttributeSubscriptionState() + } + class Primary3IntensityAttribute(val value: UByte?) + sealed class Primary3IntensityAttributeSubscriptionState { + data class Success(val value: UByte?) : Primary3IntensityAttributeSubscriptionState() + + data class Error(val exception: Exception) : Primary3IntensityAttributeSubscriptionState() + + object SubscriptionEstablished : Primary3IntensityAttributeSubscriptionState() + } + class Primary4IntensityAttribute(val value: UByte?) + sealed class Primary4IntensityAttributeSubscriptionState { + data class Success(val value: UByte?) : Primary4IntensityAttributeSubscriptionState() + + data class Error(val exception: Exception) : Primary4IntensityAttributeSubscriptionState() + + object SubscriptionEstablished : Primary4IntensityAttributeSubscriptionState() + } + class Primary5IntensityAttribute(val value: UByte?) + sealed class Primary5IntensityAttributeSubscriptionState { + data class Success(val value: UByte?) : Primary5IntensityAttributeSubscriptionState() + + data class Error(val exception: Exception) : Primary5IntensityAttributeSubscriptionState() + + object SubscriptionEstablished : Primary5IntensityAttributeSubscriptionState() + } + class Primary6IntensityAttribute(val value: UByte?) + sealed class Primary6IntensityAttributeSubscriptionState { + data class Success(val value: UByte?) : Primary6IntensityAttributeSubscriptionState() + + data class Error(val exception: Exception) : Primary6IntensityAttributeSubscriptionState() + + object SubscriptionEstablished : Primary6IntensityAttributeSubscriptionState() + } + class ColorPointRIntensityAttribute(val value: UByte?) + sealed class ColorPointRIntensityAttributeSubscriptionState { + data class Success(val value: UByte?) : ColorPointRIntensityAttributeSubscriptionState() + + data class Error(val exception: Exception) : ColorPointRIntensityAttributeSubscriptionState() + + object SubscriptionEstablished : ColorPointRIntensityAttributeSubscriptionState() + } + class ColorPointGIntensityAttribute(val value: UByte?) + sealed class ColorPointGIntensityAttributeSubscriptionState { + data class Success(val value: UByte?) : ColorPointGIntensityAttributeSubscriptionState() + + data class Error(val exception: Exception) : ColorPointGIntensityAttributeSubscriptionState() + + object SubscriptionEstablished : ColorPointGIntensityAttributeSubscriptionState() + } + class ColorPointBIntensityAttribute(val value: UByte?) + sealed class ColorPointBIntensityAttributeSubscriptionState { + data class Success(val value: UByte?) : ColorPointBIntensityAttributeSubscriptionState() + + data class Error(val exception: Exception) : ColorPointBIntensityAttributeSubscriptionState() + + object SubscriptionEstablished : ColorPointBIntensityAttributeSubscriptionState() + } + class StartUpColorTemperatureMiredsAttribute(val value: UShort?) + sealed class StartUpColorTemperatureMiredsAttributeSubscriptionState { + data class Success(val value: UShort?) : + StartUpColorTemperatureMiredsAttributeSubscriptionState() + + data class Error(val exception: Exception) : + StartUpColorTemperatureMiredsAttributeSubscriptionState() + + object SubscriptionEstablished : StartUpColorTemperatureMiredsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun moveToHue( hue: UByte, direction: UByte, @@ -862,6 +992,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeCurrentHueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currenthue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentSaturationAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 1u @@ -898,6 +1083,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeCurrentSaturationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentsaturation attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRemainingTimeAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2u @@ -934,6 +1176,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeRemainingTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Remainingtime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentXAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 3u @@ -970,6 +1267,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeCurrentXAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentx attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentYAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 4u @@ -1006,6 +1358,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeCurrentYAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currenty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDriftCompensationAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 5u @@ -1042,6 +1449,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeDriftCompensationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Driftcompensation attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCompensationTextAttribute(): String? { val ATTRIBUTE_ID: UInt = 6u @@ -1078,6 +1542,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeCompensationTextAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Compensationtext attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorTemperatureMiredsAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 7u @@ -1114,6 +1635,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorTemperatureMiredsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colortemperaturemireds attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 8u @@ -1145,6 +1723,56 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Colormode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOptionsAttribute(): UByte { val ATTRIBUTE_ID: UInt = 15u @@ -1216,6 +1844,56 @@ class ColorControlCluster( } } + suspend fun subscribeOptionsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 15u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Options attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfPrimariesAttribute(): NumberOfPrimariesAttribute { val ATTRIBUTE_ID: UInt = 16u @@ -1253,6 +1931,64 @@ class ColorControlCluster( return NumberOfPrimariesAttribute(decodedValue) } + suspend fun subscribeNumberOfPrimariesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NumberOfPrimariesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofprimaries attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NumberOfPrimariesAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NumberOfPrimariesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary1XAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 17u @@ -1289,6 +2025,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary1XAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary1x attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary1YAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 18u @@ -1325,6 +2116,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary1YAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary1y attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary1IntensityAttribute(): Primary1IntensityAttribute { val ATTRIBUTE_ID: UInt = 19u @@ -1366,11 +2212,73 @@ class ColorControlCluster( return Primary1IntensityAttribute(decodedValue) } - suspend fun readPrimary2XAttribute(): UShort? { - val ATTRIBUTE_ID: UInt = 21u + suspend fun subscribePrimary1IntensityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) - val attributePath = - AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + Primary1IntensityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Primary1intensity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(Primary1IntensityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(Primary1IntensityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readPrimary2XAttribute(): UShort? { + val ATTRIBUTE_ID: UInt = 21u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) @@ -1402,6 +2310,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary2XAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 21u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary2x attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary2YAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 22u @@ -1438,6 +2401,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary2YAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 22u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary2y attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary2IntensityAttribute(): Primary2IntensityAttribute { val ATTRIBUTE_ID: UInt = 23u @@ -1479,6 +2497,68 @@ class ColorControlCluster( return Primary2IntensityAttribute(decodedValue) } + suspend fun subscribePrimary2IntensityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 23u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + Primary2IntensityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Primary2intensity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(Primary2IntensityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(Primary2IntensityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary3XAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 25u @@ -1515,6 +2595,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary3XAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 25u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary3x attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary3YAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 26u @@ -1551,6 +2686,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary3YAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 26u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary3y attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary3IntensityAttribute(): Primary3IntensityAttribute { val ATTRIBUTE_ID: UInt = 27u @@ -1592,6 +2782,68 @@ class ColorControlCluster( return Primary3IntensityAttribute(decodedValue) } + suspend fun subscribePrimary3IntensityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 27u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + Primary3IntensityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Primary3intensity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(Primary3IntensityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(Primary3IntensityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary4XAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 32u @@ -1628,6 +2880,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary4XAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 32u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary4x attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary4YAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 33u @@ -1664,6 +2971,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary4YAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 33u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary4y attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary4IntensityAttribute(): Primary4IntensityAttribute { val ATTRIBUTE_ID: UInt = 34u @@ -1705,6 +3067,68 @@ class ColorControlCluster( return Primary4IntensityAttribute(decodedValue) } + suspend fun subscribePrimary4IntensityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 34u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + Primary4IntensityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Primary4intensity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(Primary4IntensityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(Primary4IntensityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary5XAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 36u @@ -1741,6 +3165,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary5XAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 36u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary5x attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary5YAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 37u @@ -1777,6 +3256,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary5YAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 37u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary5y attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary5IntensityAttribute(): Primary5IntensityAttribute { val ATTRIBUTE_ID: UInt = 38u @@ -1818,6 +3352,68 @@ class ColorControlCluster( return Primary5IntensityAttribute(decodedValue) } + suspend fun subscribePrimary5IntensityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 38u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + Primary5IntensityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Primary5intensity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(Primary5IntensityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(Primary5IntensityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary6XAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 40u @@ -1854,6 +3450,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary6XAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 40u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary6x attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary6YAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 41u @@ -1890,6 +3541,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribePrimary6YAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 41u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Primary6y attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPrimary6IntensityAttribute(): Primary6IntensityAttribute { val ATTRIBUTE_ID: UInt = 42u @@ -1931,6 +3637,68 @@ class ColorControlCluster( return Primary6IntensityAttribute(decodedValue) } + suspend fun subscribePrimary6IntensityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 42u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + Primary6IntensityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Primary6intensity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(Primary6IntensityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(Primary6IntensityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWhitePointXAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 48u @@ -2007,6 +3775,61 @@ class ColorControlCluster( } } + suspend fun subscribeWhitePointXAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 48u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Whitepointx attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWhitePointYAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 49u @@ -2083,6 +3906,61 @@ class ColorControlCluster( } } + suspend fun subscribeWhitePointYAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 49u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Whitepointy attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorPointRXAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 50u @@ -2159,13 +4037,68 @@ class ColorControlCluster( } } - suspend fun readColorPointRYAttribute(): UShort? { - val ATTRIBUTE_ID: UInt = 51u - - val attributePath = - AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + suspend fun subscribeColorPointRXAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 50u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) - val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Colorpointrx attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readColorPointRYAttribute(): UShort? { + val ATTRIBUTE_ID: UInt = 51u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) val response = controller.read(readRequest) @@ -2235,6 +4168,61 @@ class ColorControlCluster( } } + suspend fun subscribeColorPointRYAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 51u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Colorpointry attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorPointRIntensityAttribute(): ColorPointRIntensityAttribute { val ATTRIBUTE_ID: UInt = 52u @@ -2319,6 +4307,68 @@ class ColorControlCluster( } } + suspend fun subscribeColorPointRIntensityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 52u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ColorPointRIntensityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colorpointrintensity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ColorPointRIntensityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ColorPointRIntensityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorPointGXAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 54u @@ -2395,6 +4445,61 @@ class ColorControlCluster( } } + suspend fun subscribeColorPointGXAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 54u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Colorpointgx attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorPointGYAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 55u @@ -2471,6 +4576,61 @@ class ColorControlCluster( } } + suspend fun subscribeColorPointGYAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 55u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Colorpointgy attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorPointGIntensityAttribute(): ColorPointGIntensityAttribute { val ATTRIBUTE_ID: UInt = 56u @@ -2555,6 +4715,68 @@ class ColorControlCluster( } } + suspend fun subscribeColorPointGIntensityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 56u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ColorPointGIntensityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colorpointgintensity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ColorPointGIntensityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ColorPointGIntensityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorPointBXAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 58u @@ -2631,6 +4853,61 @@ class ColorControlCluster( } } + suspend fun subscribeColorPointBXAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 58u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Colorpointbx attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorPointBYAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 59u @@ -2707,6 +4984,61 @@ class ColorControlCluster( } } + suspend fun subscribeColorPointBYAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 59u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Colorpointby attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorPointBIntensityAttribute(): ColorPointBIntensityAttribute { val ATTRIBUTE_ID: UInt = 60u @@ -2791,6 +5123,68 @@ class ColorControlCluster( } } + suspend fun subscribeColorPointBIntensityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 60u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ColorPointBIntensityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colorpointbintensity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ColorPointBIntensityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ColorPointBIntensityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEnhancedCurrentHueAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16384u @@ -2827,6 +5221,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeEnhancedCurrentHueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16384u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Enhancedcurrenthue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEnhancedColorModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 16385u @@ -2858,6 +5309,58 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeEnhancedColorModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16385u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Enhancedcolormode attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorLoopActiveAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 16386u @@ -2894,6 +5397,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorLoopActiveAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16386u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colorloopactive attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorLoopDirectionAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 16387u @@ -2930,6 +5490,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorLoopDirectionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16387u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colorloopdirection attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorLoopTimeAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16388u @@ -2966,6 +5583,61 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorLoopTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16388u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Colorlooptime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorLoopStartEnhancedHueAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16389u @@ -3002,6 +5674,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorLoopStartEnhancedHueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16389u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colorloopstartenhancedhue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorLoopStoredEnhancedHueAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16390u @@ -3038,6 +5767,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorLoopStoredEnhancedHueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16390u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colorloopstoredenhancedhue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorCapabilitiesAttribute(): UShort { val ATTRIBUTE_ID: UInt = 16394u @@ -3069,6 +5855,58 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorCapabilitiesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16394u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colorcapabilities attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorTempPhysicalMinMiredsAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16395u @@ -3105,6 +5943,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorTempPhysicalMinMiredsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16395u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colortempphysicalminmireds attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readColorTempPhysicalMaxMiredsAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16396u @@ -3141,6 +6036,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeColorTempPhysicalMaxMiredsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16396u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Colortempphysicalmaxmireds attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCoupleColorTempToLevelMinMiredsAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16397u @@ -3179,6 +6131,63 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeCoupleColorTempToLevelMinMiredsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16397u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Couplecolortemptolevelminmireds attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartUpColorTemperatureMiredsAttribute(): StartUpColorTemperatureMiredsAttribute { val ATTRIBUTE_ID: UInt = 16400u @@ -3265,6 +6274,70 @@ class ColorControlCluster( } } + suspend fun subscribeStartUpColorTemperatureMiredsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16400u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StartUpColorTemperatureMiredsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Startupcolortemperaturemireds attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(StartUpColorTemperatureMiredsAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StartUpColorTemperatureMiredsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -3303,6 +6376,65 @@ class ColorControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -3341,6 +6473,65 @@ class ColorControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -3379,6 +6570,63 @@ class ColorControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -3417,6 +6665,63 @@ class ColorControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -3448,6 +6753,56 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -3479,6 +6834,58 @@ class ColorControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ColorControlCluster::class.java.name) const val CLUSTER_ID: UInt = 768u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentAppObserverCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentAppObserverCluster.kt index 645714bdf66e1b..68ca2fa84898cb 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentAppObserverCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentAppObserverCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,12 +47,44 @@ class ContentAppObserverCluster( class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun contentAppMessage( data: String?, encodingHint: String, @@ -164,6 +202,65 @@ class ContentAppObserverCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -202,6 +299,65 @@ class ContentAppObserverCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -240,6 +396,63 @@ class ContentAppObserverCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -278,6 +491,63 @@ class ContentAppObserverCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -309,6 +579,56 @@ class ContentAppObserverCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -340,6 +660,58 @@ class ContentAppObserverCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ContentAppObserverCluster::class.java.name) const val CLUSTER_ID: UInt = 1296u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentControlCluster.kt index 4fc07614a3915a..327d7b9645c408 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentControlCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,16 +49,67 @@ class ContentControlCluster( class OnDemandRatingsAttribute(val value: List?) + sealed class OnDemandRatingsAttributeSubscriptionState { + data class Success(val value: List?) : + OnDemandRatingsAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnDemandRatingsAttributeSubscriptionState() + + object SubscriptionEstablished : OnDemandRatingsAttributeSubscriptionState() + } + class ScheduledContentRatingsAttribute(val value: List?) + sealed class ScheduledContentRatingsAttributeSubscriptionState { + data class Success(val value: List?) : + ScheduledContentRatingsAttributeSubscriptionState() + + data class Error(val exception: Exception) : + ScheduledContentRatingsAttributeSubscriptionState() + + object SubscriptionEstablished : ScheduledContentRatingsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun updatePIN(oldPIN: String?, newPIN: String, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -313,6 +372,56 @@ class ContentControlCluster( return decodedValue } + suspend fun subscribeEnabledAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Enabled attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnDemandRatingsAttribute(): OnDemandRatingsAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -355,6 +464,69 @@ class ContentControlCluster( return OnDemandRatingsAttribute(decodedValue) } + suspend fun subscribeOnDemandRatingsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnDemandRatingsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Ondemandratings attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ContentControlClusterRatingNameStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(OnDemandRatingsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnDemandRatingsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnDemandRatingThresholdAttribute(): String? { val ATTRIBUTE_ID: UInt = 2u @@ -391,6 +563,63 @@ class ContentControlCluster( return decodedValue } + suspend fun subscribeOnDemandRatingThresholdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Ondemandratingthreshold attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readScheduledContentRatingsAttribute(): ScheduledContentRatingsAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -433,6 +662,69 @@ class ContentControlCluster( return ScheduledContentRatingsAttribute(decodedValue) } + suspend fun subscribeScheduledContentRatingsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ScheduledContentRatingsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Scheduledcontentratings attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ContentControlClusterRatingNameStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ScheduledContentRatingsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ScheduledContentRatingsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readScheduledContentRatingThresholdAttribute(): String? { val ATTRIBUTE_ID: UInt = 4u @@ -471,6 +763,63 @@ class ContentControlCluster( return decodedValue } + suspend fun subscribeScheduledContentRatingThresholdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Scheduledcontentratingthreshold attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readScreenDailyTimeAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 5u @@ -507,6 +856,63 @@ class ContentControlCluster( return decodedValue } + suspend fun subscribeScreenDailyTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Screendailytime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRemainingScreenTimeAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -543,6 +949,63 @@ class ContentControlCluster( return decodedValue } + suspend fun subscribeRemainingScreenTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Remainingscreentime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBlockUnratedAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 7u @@ -574,6 +1037,56 @@ class ContentControlCluster( return decodedValue } + suspend fun subscribeBlockUnratedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Blockunrated attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -612,6 +1125,65 @@ class ContentControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -650,6 +1222,65 @@ class ContentControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -688,6 +1319,63 @@ class ContentControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -726,6 +1414,63 @@ class ContentControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -757,6 +1502,56 @@ class ContentControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -788,6 +1583,58 @@ class ContentControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ContentControlCluster::class.java.name) const val CLUSTER_ID: UInt = 1295u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentLauncherCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentLauncherCluster.kt index e3acd6cde3d2f9..ae50ff527a8e2c 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentLauncherCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ContentLauncherCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,14 +47,54 @@ class ContentLauncherCluster( class AcceptHeaderAttribute(val value: List?) + sealed class AcceptHeaderAttributeSubscriptionState { + data class Success(val value: List?) : AcceptHeaderAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptHeaderAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptHeaderAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun launchContent( search: ContentLauncherClusterContentSearchStruct, autoPlay: Boolean, @@ -249,6 +295,67 @@ class ContentLauncherCluster( return AcceptHeaderAttribute(decodedValue) } + suspend fun subscribeAcceptHeaderAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptHeaderAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Acceptheader attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getString(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(AcceptHeaderAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptHeaderAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedStreamingProtocolsAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 1u @@ -285,6 +392,63 @@ class ContentLauncherCluster( return decodedValue } + suspend fun subscribeSupportedStreamingProtocolsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedstreamingprotocols attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -323,6 +487,65 @@ class ContentLauncherCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -361,6 +584,65 @@ class ContentLauncherCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -399,6 +681,63 @@ class ContentLauncherCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -437,6 +776,63 @@ class ContentLauncherCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -468,6 +864,56 @@ class ContentLauncherCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -499,6 +945,58 @@ class ContentLauncherCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ContentLauncherCluster::class.java.name) const val CLUSTER_ID: UInt = 1290u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/DemandResponseLoadControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/DemandResponseLoadControlCluster.kt index 0e26876329cb5f..af0c8860f08d12 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/DemandResponseLoadControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/DemandResponseLoadControlCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -44,20 +51,79 @@ class DemandResponseLoadControlCluster( val value: List ) + sealed class LoadControlProgramsAttributeSubscriptionState { + data class Success(val value: List) : + LoadControlProgramsAttributeSubscriptionState() + + data class Error(val exception: Exception) : LoadControlProgramsAttributeSubscriptionState() + + object SubscriptionEstablished : LoadControlProgramsAttributeSubscriptionState() + } + class EventsAttribute(val value: List) + sealed class EventsAttributeSubscriptionState { + data class Success(val value: List) : + EventsAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventsAttributeSubscriptionState() + + object SubscriptionEstablished : EventsAttributeSubscriptionState() + } + class ActiveEventsAttribute( val value: List ) + sealed class ActiveEventsAttributeSubscriptionState { + data class Success(val value: List) : + ActiveEventsAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveEventsAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveEventsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun registerLoadControlProgramRequest( loadControlProgram: DemandResponseLoadControlClusterLoadControlProgramStruct, timedInvokeTimeout: Duration? = null @@ -219,6 +285,70 @@ class DemandResponseLoadControlCluster( return LoadControlProgramsAttribute(decodedValue) } + suspend fun subscribeLoadControlProgramsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LoadControlProgramsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Loadcontrolprograms attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + DemandResponseLoadControlClusterLoadControlProgramStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + + emit(LoadControlProgramsAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LoadControlProgramsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfLoadControlProgramsAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -250,6 +380,58 @@ class DemandResponseLoadControlCluster( return decodedValue } + suspend fun subscribeNumberOfLoadControlProgramsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofloadcontrolprograms attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventsAttribute(): EventsAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -290,6 +472,68 @@ class DemandResponseLoadControlCluster( return EventsAttribute(decodedValue) } + suspend fun subscribeEventsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Events attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + DemandResponseLoadControlClusterLoadControlEventStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + + emit(EventsAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveEventsAttribute(): ActiveEventsAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -330,6 +574,68 @@ class DemandResponseLoadControlCluster( return ActiveEventsAttribute(decodedValue) } + suspend fun subscribeActiveEventsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveEventsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Activeevents attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + DemandResponseLoadControlClusterLoadControlEventStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + + emit(ActiveEventsAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveEventsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfEventsPerProgramAttribute(): UByte { val ATTRIBUTE_ID: UInt = 4u @@ -361,6 +667,58 @@ class DemandResponseLoadControlCluster( return decodedValue } + suspend fun subscribeNumberOfEventsPerProgramAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofeventsperprogram attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfTransitionsAttribute(): UByte { val ATTRIBUTE_ID: UInt = 5u @@ -392,6 +750,58 @@ class DemandResponseLoadControlCluster( return decodedValue } + suspend fun subscribeNumberOfTransitionsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberoftransitions attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDefaultRandomStartAttribute(): UByte { val ATTRIBUTE_ID: UInt = 6u @@ -463,6 +873,58 @@ class DemandResponseLoadControlCluster( } } + suspend fun subscribeDefaultRandomStartAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Defaultrandomstart attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDefaultRandomDurationAttribute(): UByte { val ATTRIBUTE_ID: UInt = 7u @@ -537,6 +999,58 @@ class DemandResponseLoadControlCluster( } } + suspend fun subscribeDefaultRandomDurationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Defaultrandomduration attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -575,6 +1089,65 @@ class DemandResponseLoadControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -613,6 +1186,65 @@ class DemandResponseLoadControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -651,6 +1283,63 @@ class DemandResponseLoadControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -689,6 +1378,63 @@ class DemandResponseLoadControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -720,6 +1466,56 @@ class DemandResponseLoadControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -751,6 +1547,58 @@ class DemandResponseLoadControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(DemandResponseLoadControlCluster::class.java.name) const val CLUSTER_ID: UInt = 150u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/DescriptorCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/DescriptorCluster.kt index 51e88cc6500974..5ff9420be9baf0 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/DescriptorCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/DescriptorCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -30,22 +37,96 @@ import matter.tlv.TlvReader class DescriptorCluster(private val controller: MatterController, private val endpointId: UShort) { class DeviceTypeListAttribute(val value: List) + sealed class DeviceTypeListAttributeSubscriptionState { + data class Success(val value: List) : + DeviceTypeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : DeviceTypeListAttributeSubscriptionState() + + object SubscriptionEstablished : DeviceTypeListAttributeSubscriptionState() + } + class ServerListAttribute(val value: List) + sealed class ServerListAttributeSubscriptionState { + data class Success(val value: List) : ServerListAttributeSubscriptionState() + + data class Error(val exception: Exception) : ServerListAttributeSubscriptionState() + + object SubscriptionEstablished : ServerListAttributeSubscriptionState() + } + class ClientListAttribute(val value: List) + sealed class ClientListAttributeSubscriptionState { + data class Success(val value: List) : ClientListAttributeSubscriptionState() + + data class Error(val exception: Exception) : ClientListAttributeSubscriptionState() + + object SubscriptionEstablished : ClientListAttributeSubscriptionState() + } + class PartsListAttribute(val value: List) + sealed class PartsListAttributeSubscriptionState { + data class Success(val value: List) : PartsListAttributeSubscriptionState() + + data class Error(val exception: Exception) : PartsListAttributeSubscriptionState() + + object SubscriptionEstablished : PartsListAttributeSubscriptionState() + } + class TagListAttribute(val value: List?) + sealed class TagListAttributeSubscriptionState { + data class Success(val value: List?) : + TagListAttributeSubscriptionState() + + data class Error(val exception: Exception) : TagListAttributeSubscriptionState() + + object SubscriptionEstablished : TagListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readDeviceTypeListAttribute(): DeviceTypeListAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -84,6 +165,65 @@ class DescriptorCluster(private val controller: MatterController, private val en return DeviceTypeListAttribute(decodedValue) } + suspend fun subscribeDeviceTypeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DeviceTypeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Devicetypelist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(DescriptorClusterDeviceTypeStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(DeviceTypeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(DeviceTypeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readServerListAttribute(): ServerListAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -122,6 +262,63 @@ class DescriptorCluster(private val controller: MatterController, private val en return ServerListAttribute(decodedValue) } + suspend fun subscribeServerListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ServerListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Serverlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(ServerListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ServerListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClientListAttribute(): ClientListAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -160,6 +357,63 @@ class DescriptorCluster(private val controller: MatterController, private val en return ClientListAttribute(decodedValue) } + suspend fun subscribeClientListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ClientListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Clientlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(ClientListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ClientListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPartsListAttribute(): PartsListAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -198,6 +452,63 @@ class DescriptorCluster(private val controller: MatterController, private val en return PartsListAttribute(decodedValue) } + suspend fun subscribePartsListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PartsListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Partslist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUShort(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(PartsListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(PartsListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTagListAttribute(): TagListAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -240,6 +551,67 @@ class DescriptorCluster(private val controller: MatterController, private val en return TagListAttribute(decodedValue) } + suspend fun subscribeTagListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TagListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Taglist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(DescriptorClusterSemanticTagStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(TagListAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(TagListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -278,6 +650,65 @@ class DescriptorCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -316,6 +747,65 @@ class DescriptorCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -354,6 +844,63 @@ class DescriptorCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -392,6 +939,63 @@ class DescriptorCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -423,6 +1027,56 @@ class DescriptorCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -454,6 +1108,58 @@ class DescriptorCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(DescriptorCluster::class.java.name) const val CLUSTER_ID: UInt = 29u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/DeviceEnergyManagementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/DeviceEnergyManagementCluster.kt index 2456d29fe96c52..8481bbf3ccf788 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/DeviceEnergyManagementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/DeviceEnergyManagementCluster.kt @@ -20,11 +20,20 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse +import matter.controller.LongSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,16 +50,67 @@ class DeviceEnergyManagementCluster( val value: List? ) + sealed class PowerAdjustmentCapabilityAttributeSubscriptionState { + data class Success(val value: List?) : + PowerAdjustmentCapabilityAttributeSubscriptionState() + + data class Error(val exception: Exception) : + PowerAdjustmentCapabilityAttributeSubscriptionState() + + object SubscriptionEstablished : PowerAdjustmentCapabilityAttributeSubscriptionState() + } + class ForecastAttribute(val value: DeviceEnergyManagementClusterForecastStruct?) + sealed class ForecastAttributeSubscriptionState { + data class Success(val value: DeviceEnergyManagementClusterForecastStruct?) : + ForecastAttributeSubscriptionState() + + data class Error(val exception: Exception) : ForecastAttributeSubscriptionState() + + object SubscriptionEstablished : ForecastAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun powerAdjustRequest( power: Long, duration: UInt, @@ -251,6 +311,56 @@ class DeviceEnergyManagementCluster( return decodedValue } + suspend fun subscribeESATypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Esatype attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readESACanGenerateAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 1u @@ -282,6 +392,58 @@ class DeviceEnergyManagementCluster( return decodedValue } + suspend fun subscribeESACanGenerateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Esacangenerate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readESAStateAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -313,6 +475,56 @@ class DeviceEnergyManagementCluster( return decodedValue } + suspend fun subscribeESAStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Esastate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAbsMinPowerAttribute(): Long { val ATTRIBUTE_ID: UInt = 3u @@ -344,6 +556,56 @@ class DeviceEnergyManagementCluster( return decodedValue } + suspend fun subscribeAbsMinPowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Absminpower attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long = tlvReader.getLong(AnonymousTag) + + emit(LongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAbsMaxPowerAttribute(): Long { val ATTRIBUTE_ID: UInt = 4u @@ -375,6 +637,56 @@ class DeviceEnergyManagementCluster( return decodedValue } + suspend fun subscribeAbsMaxPowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Absmaxpower attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long = tlvReader.getLong(AnonymousTag) + + emit(LongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPowerAdjustmentCapabilityAttribute(): PowerAdjustmentCapabilityAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -422,6 +734,81 @@ class DeviceEnergyManagementCluster( return PowerAdjustmentCapabilityAttribute(decodedValue) } + suspend fun subscribePowerAdjustmentCapabilityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PowerAdjustmentCapabilityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Poweradjustmentcapability attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + DeviceEnergyManagementClusterPowerAdjustStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(PowerAdjustmentCapabilityAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PowerAdjustmentCapabilityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readForecastAttribute(): ForecastAttribute { val ATTRIBUTE_ID: UInt = 6u @@ -463,6 +850,66 @@ class DeviceEnergyManagementCluster( return ForecastAttribute(decodedValue) } + suspend fun subscribeForecastAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ForecastAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Forecast attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: DeviceEnergyManagementClusterForecastStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + DeviceEnergyManagementClusterForecastStruct.fromTlv(AnonymousTag, tlvReader) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ForecastAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ForecastAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -501,6 +948,65 @@ class DeviceEnergyManagementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -539,6 +1045,65 @@ class DeviceEnergyManagementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -577,6 +1142,63 @@ class DeviceEnergyManagementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -615,6 +1237,63 @@ class DeviceEnergyManagementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -646,6 +1325,56 @@ class DeviceEnergyManagementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -677,6 +1406,58 @@ class DeviceEnergyManagementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(DeviceEnergyManagementCluster::class.java.name) const val CLUSTER_ID: UInt = 152u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/DiagnosticLogsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/DiagnosticLogsCluster.kt index 44e346e7c46d35..0838a9e113ed40 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/DiagnosticLogsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/DiagnosticLogsCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -46,12 +52,44 @@ class DiagnosticLogsCluster( class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun retrieveLogsRequest( intent: UByte, requestedProtocol: UByte, @@ -197,6 +235,65 @@ class DiagnosticLogsCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -235,6 +332,65 @@ class DiagnosticLogsCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -273,6 +429,63 @@ class DiagnosticLogsCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -311,6 +524,63 @@ class DiagnosticLogsCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -342,6 +612,56 @@ class DiagnosticLogsCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -373,6 +693,58 @@ class DiagnosticLogsCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(DiagnosticLogsCluster::class.java.name) const val CLUSTER_ID: UInt = 50u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherAlarmCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherAlarmCluster.kt index 0a72b49309b012..b13261710a3be1 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherAlarmCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherAlarmCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -39,12 +45,44 @@ class DishwasherAlarmCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun reset(alarms: UInt, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -118,6 +156,56 @@ class DishwasherAlarmCluster( return decodedValue } + suspend fun subscribeMaskAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Mask attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLatchAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 1u @@ -154,6 +242,61 @@ class DishwasherAlarmCluster( return decodedValue } + suspend fun subscribeLatchAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Latch attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStateAttribute(): UInt { val ATTRIBUTE_ID: UInt = 2u @@ -185,6 +328,56 @@ class DishwasherAlarmCluster( return decodedValue } + suspend fun subscribeStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "State attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedAttribute(): UInt { val ATTRIBUTE_ID: UInt = 3u @@ -216,6 +409,56 @@ class DishwasherAlarmCluster( return decodedValue } + suspend fun subscribeSupportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Supported attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -254,6 +497,65 @@ class DishwasherAlarmCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -292,6 +594,65 @@ class DishwasherAlarmCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -330,6 +691,63 @@ class DishwasherAlarmCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -368,6 +786,63 @@ class DishwasherAlarmCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -399,6 +874,56 @@ class DishwasherAlarmCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -430,6 +955,58 @@ class DishwasherAlarmCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(DishwasherAlarmCluster::class.java.name) const val CLUSTER_ID: UInt = 93u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherModeCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherModeCluster.kt index be86c564699aa4..84be2a10cc560a 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherModeCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/DishwasherModeCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -44,18 +51,75 @@ class DishwasherModeCluster( class SupportedModesAttribute(val value: List) + sealed class SupportedModesAttributeSubscriptionState { + data class Success(val value: List) : + SupportedModesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedModesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedModesAttributeSubscriptionState() + } + class StartUpModeAttribute(val value: UByte?) + sealed class StartUpModeAttributeSubscriptionState { + data class Success(val value: UByte?) : StartUpModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : StartUpModeAttributeSubscriptionState() + + object SubscriptionEstablished : StartUpModeAttributeSubscriptionState() + } + class OnModeAttribute(val value: UByte?) + sealed class OnModeAttributeSubscriptionState { + data class Success(val value: UByte?) : OnModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnModeAttributeSubscriptionState() + + object SubscriptionEstablished : OnModeAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun changeToMode( newMode: UByte, timedInvokeTimeout: Duration? = null @@ -158,6 +222,65 @@ class DishwasherModeCluster( return SupportedModesAttribute(decodedValue) } + suspend fun subscribeSupportedModesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedModesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedmodes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(DishwasherModeClusterModeOptionStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(SupportedModesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedModesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -189,6 +312,56 @@ class DishwasherModeCluster( return decodedValue } + suspend fun subscribeCurrentModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartUpModeAttribute(): StartUpModeAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -270,6 +443,66 @@ class DishwasherModeCluster( } } + suspend fun subscribeStartUpModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StartUpModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Startupmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StartUpModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StartUpModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnModeAttribute(): OnModeAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -351,6 +584,66 @@ class DishwasherModeCluster( } } + suspend fun subscribeOnModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Onmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OnModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -389,6 +682,65 @@ class DishwasherModeCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -427,6 +779,65 @@ class DishwasherModeCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -465,6 +876,63 @@ class DishwasherModeCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -503,6 +971,63 @@ class DishwasherModeCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -534,6 +1059,56 @@ class DishwasherModeCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -565,6 +1140,58 @@ class DishwasherModeCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(DishwasherModeCluster::class.java.name) const val CLUSTER_ID: UInt = 89u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/DoorLockCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/DoorLockCluster.kt index aa365a093b48a5..98640cae466121 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/DoorLockCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/DoorLockCluster.kt @@ -20,11 +20,20 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -93,16 +102,64 @@ class DoorLockCluster(private val controller: MatterController, private val endp class LockStateAttribute(val value: UByte?) + sealed class LockStateAttributeSubscriptionState { + data class Success(val value: UByte?) : LockStateAttributeSubscriptionState() + + data class Error(val exception: Exception) : LockStateAttributeSubscriptionState() + + object SubscriptionEstablished : LockStateAttributeSubscriptionState() + } + class DoorStateAttribute(val value: UByte?) + sealed class DoorStateAttributeSubscriptionState { + data class Success(val value: UByte?) : DoorStateAttributeSubscriptionState() + + data class Error(val exception: Exception) : DoorStateAttributeSubscriptionState() + + object SubscriptionEstablished : DoorStateAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun lockDoor(PINCode: ByteArray?, timedInvokeTimeout: Duration) { val commandId: UInt = 0u @@ -1369,6 +1426,62 @@ class DoorLockCluster(private val controller: MatterController, private val endp return LockStateAttribute(decodedValue) } + suspend fun subscribeLockStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LockStateAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Lockstate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LockStateAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LockStateAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLockTypeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -1400,6 +1513,56 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeLockTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Locktype attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActuatorEnabledAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 2u @@ -1431,6 +1594,58 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeActuatorEnabledAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Actuatorenabled attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDoorStateAttribute(): DoorStateAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -1472,6 +1687,66 @@ class DoorLockCluster(private val controller: MatterController, private val endp return DoorStateAttribute(decodedValue) } + suspend fun subscribeDoorStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DoorStateAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Doorstate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(DoorStateAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(DoorStateAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDoorOpenEventsAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -1548,6 +1823,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeDoorOpenEventsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Dooropenevents attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDoorClosedEventsAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 5u @@ -1624,6 +1956,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeDoorClosedEventsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Doorclosedevents attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOpenPeriodAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 6u @@ -1700,6 +2089,61 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeOpenPeriodAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Openperiod attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfTotalUsersSupportedAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 17u @@ -1736,6 +2180,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeNumberOfTotalUsersSupportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberoftotaluserssupported attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfPINUsersSupportedAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 18u @@ -1772,6 +2273,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeNumberOfPINUsersSupportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofpinuserssupported attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfRFIDUsersSupportedAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 19u @@ -1808,6 +2366,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeNumberOfRFIDUsersSupportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofrfiduserssupported attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfWeekDaySchedulesSupportedPerUserAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 20u @@ -1846,6 +2461,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeNumberOfWeekDaySchedulesSupportedPerUserAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofweekdayschedulessupportedperuser attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfYearDaySchedulesSupportedPerUserAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 21u @@ -1884,6 +2556,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeNumberOfYearDaySchedulesSupportedPerUserAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 21u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofyeardayschedulessupportedperuser attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfHolidaySchedulesSupportedAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 22u @@ -1922,13 +2651,70 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } - suspend fun readMaxPINCodeLengthAttribute(): UByte? { - val ATTRIBUTE_ID: UInt = 23u - - val attributePath = - AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + suspend fun subscribeNumberOfHolidaySchedulesSupportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 22u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) - val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofholidayschedulessupported attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readMaxPINCodeLengthAttribute(): UByte? { + val ATTRIBUTE_ID: UInt = 23u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) val response = controller.read(readRequest) @@ -1958,6 +2744,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeMaxPINCodeLengthAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 23u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxpincodelength attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinPINCodeLengthAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 24u @@ -1994,6 +2837,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeMinPINCodeLengthAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 24u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minpincodelength attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxRFIDCodeLengthAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 25u @@ -2030,6 +2930,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeMaxRFIDCodeLengthAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 25u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxrfidcodelength attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinRFIDCodeLengthAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 26u @@ -2066,6 +3023,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeMinRFIDCodeLengthAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 26u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minrfidcodelength attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCredentialRulesSupportAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 27u @@ -2102,6 +3116,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeCredentialRulesSupportAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 27u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Credentialrulessupport attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfCredentialsSupportedPerUserAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 28u @@ -2140,6 +3211,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeNumberOfCredentialsSupportedPerUserAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 28u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofcredentialssupportedperuser attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLanguageAttribute(): String? { val ATTRIBUTE_ID: UInt = 33u @@ -2216,6 +3344,61 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeLanguageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 33u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Language attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLEDSettingsAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 34u @@ -2292,6 +3475,61 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeLEDSettingsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 34u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Ledsettings attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAutoRelockTimeAttribute(): UInt { val ATTRIBUTE_ID: UInt = 35u @@ -2363,6 +3601,58 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeAutoRelockTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 35u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Autorelocktime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSoundVolumeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 36u @@ -2439,6 +3729,61 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeSoundVolumeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 36u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Soundvolume attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperatingModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 37u @@ -2510,6 +3855,56 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeOperatingModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 37u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Operatingmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedOperatingModesAttribute(): UShort { val ATTRIBUTE_ID: UInt = 38u @@ -2541,6 +3936,58 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeSupportedOperatingModesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 38u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedoperatingmodes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDefaultConfigurationRegisterAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 39u @@ -2577,6 +4024,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeDefaultConfigurationRegisterAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 39u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Defaultconfigurationregister attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEnableLocalProgrammingAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 40u @@ -2656,6 +4160,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeEnableLocalProgrammingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 40u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Enablelocalprogramming attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEnableOneTouchLockingAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 41u @@ -2730,7 +4291,64 @@ class DoorLockCluster(private val controller: MatterController, private val endp logger.log(Level.WARNING, "Error at ${failure.attributePath}: ${failure.ex.message}") } - throw IllegalStateException("Write command failed with errors: \n$aggregatedErrorMessage") + throw IllegalStateException("Write command failed with errors: \n$aggregatedErrorMessage") + } + } + } + + suspend fun subscribeEnableOneTouchLockingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 41u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Enableonetouchlocking attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } } } } @@ -2814,6 +4432,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeEnableInsideStatusLEDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 42u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Enableinsidestatusled attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEnablePrivacyModeButtonAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 43u @@ -2893,6 +4568,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeEnablePrivacyModeButtonAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 43u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Enableprivacymodebutton attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLocalProgrammingFeaturesAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 44u @@ -2972,6 +4704,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeLocalProgrammingFeaturesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 44u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Localprogrammingfeatures attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWrongCodeEntryLimitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 48u @@ -3048,6 +4837,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeWrongCodeEntryLimitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 48u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Wrongcodeentrylimit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUserCodeTemporaryDisableTimeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 49u @@ -3127,6 +4973,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeUserCodeTemporaryDisableTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 49u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Usercodetemporarydisabletime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSendPINOverTheAirAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 50u @@ -3203,6 +5106,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeSendPINOverTheAirAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 50u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Sendpinovertheair attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRequirePINforRemoteOperationAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 51u @@ -3282,6 +5242,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeRequirePINforRemoteOperationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 51u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Requirepinforremoteoperation attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readExpiringUserTimeoutAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 53u @@ -3361,6 +5378,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeExpiringUserTimeoutAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 53u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Expiringusertimeout attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -3399,6 +5473,65 @@ class DoorLockCluster(private val controller: MatterController, private val endp return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -3437,6 +5570,65 @@ class DoorLockCluster(private val controller: MatterController, private val endp return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -3475,6 +5667,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -3513,6 +5762,63 @@ class DoorLockCluster(private val controller: MatterController, private val endp return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -3544,6 +5850,56 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -3575,6 +5931,58 @@ class DoorLockCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(DoorLockCluster::class.java.name) const val CLUSTER_ID: UInt = 257u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalEnergyMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalEnergyMeasurementCluster.kt index b6712691a6d7cd..8be25c67fbcda4 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalEnergyMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalEnergyMeasurementCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,30 +40,109 @@ class ElectricalEnergyMeasurementCluster( ) { class AccuracyAttribute(val value: ElectricalEnergyMeasurementClusterMeasurementAccuracyStruct) + sealed class AccuracyAttributeSubscriptionState { + data class Success(val value: ElectricalEnergyMeasurementClusterMeasurementAccuracyStruct) : + AccuracyAttributeSubscriptionState() + + data class Error(val exception: Exception) : AccuracyAttributeSubscriptionState() + + object SubscriptionEstablished : AccuracyAttributeSubscriptionState() + } + class CumulativeEnergyImportedAttribute( val value: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct? ) + sealed class CumulativeEnergyImportedAttributeSubscriptionState { + data class Success(val value: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct?) : + CumulativeEnergyImportedAttributeSubscriptionState() + + data class Error(val exception: Exception) : + CumulativeEnergyImportedAttributeSubscriptionState() + + object SubscriptionEstablished : CumulativeEnergyImportedAttributeSubscriptionState() + } + class CumulativeEnergyExportedAttribute( val value: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct? ) + sealed class CumulativeEnergyExportedAttributeSubscriptionState { + data class Success(val value: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct?) : + CumulativeEnergyExportedAttributeSubscriptionState() + + data class Error(val exception: Exception) : + CumulativeEnergyExportedAttributeSubscriptionState() + + object SubscriptionEstablished : CumulativeEnergyExportedAttributeSubscriptionState() + } + class PeriodicEnergyImportedAttribute( val value: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct? ) + sealed class PeriodicEnergyImportedAttributeSubscriptionState { + data class Success(val value: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct?) : + PeriodicEnergyImportedAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeriodicEnergyImportedAttributeSubscriptionState() + + object SubscriptionEstablished : PeriodicEnergyImportedAttributeSubscriptionState() + } + class PeriodicEnergyExportedAttribute( val value: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct? ) + sealed class PeriodicEnergyExportedAttributeSubscriptionState { + data class Success(val value: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct?) : + PeriodicEnergyExportedAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeriodicEnergyExportedAttributeSubscriptionState() + + object SubscriptionEstablished : PeriodicEnergyExportedAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readAccuracyAttribute(): AccuracyAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -89,6 +175,60 @@ class ElectricalEnergyMeasurementCluster( return AccuracyAttribute(decodedValue) } + suspend fun subscribeAccuracyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AccuracyAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Accuracy attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ElectricalEnergyMeasurementClusterMeasurementAccuracyStruct = + ElectricalEnergyMeasurementClusterMeasurementAccuracyStruct.fromTlv( + AnonymousTag, + tlvReader + ) + + emit(AccuracyAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AccuracyAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCumulativeEnergyImportedAttribute(): CumulativeEnergyImportedAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -130,6 +270,71 @@ class ElectricalEnergyMeasurementCluster( return CumulativeEnergyImportedAttribute(decodedValue) } + suspend fun subscribeCumulativeEnergyImportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CumulativeEnergyImportedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Cumulativeenergyimported attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + ElectricalEnergyMeasurementClusterEnergyMeasurementStruct.fromTlv( + AnonymousTag, + tlvReader + ) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CumulativeEnergyImportedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CumulativeEnergyImportedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCumulativeEnergyExportedAttribute(): CumulativeEnergyExportedAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -171,6 +376,71 @@ class ElectricalEnergyMeasurementCluster( return CumulativeEnergyExportedAttribute(decodedValue) } + suspend fun subscribeCumulativeEnergyExportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CumulativeEnergyExportedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Cumulativeenergyexported attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + ElectricalEnergyMeasurementClusterEnergyMeasurementStruct.fromTlv( + AnonymousTag, + tlvReader + ) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CumulativeEnergyExportedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CumulativeEnergyExportedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeriodicEnergyImportedAttribute(): PeriodicEnergyImportedAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -212,6 +482,71 @@ class ElectricalEnergyMeasurementCluster( return PeriodicEnergyImportedAttribute(decodedValue) } + suspend fun subscribePeriodicEnergyImportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeriodicEnergyImportedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Periodicenergyimported attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + ElectricalEnergyMeasurementClusterEnergyMeasurementStruct.fromTlv( + AnonymousTag, + tlvReader + ) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeriodicEnergyImportedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeriodicEnergyImportedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeriodicEnergyExportedAttribute(): PeriodicEnergyExportedAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -253,6 +588,71 @@ class ElectricalEnergyMeasurementCluster( return PeriodicEnergyExportedAttribute(decodedValue) } + suspend fun subscribePeriodicEnergyExportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeriodicEnergyExportedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Periodicenergyexported attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ElectricalEnergyMeasurementClusterEnergyMeasurementStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + ElectricalEnergyMeasurementClusterEnergyMeasurementStruct.fromTlv( + AnonymousTag, + tlvReader + ) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeriodicEnergyExportedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeriodicEnergyExportedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -291,6 +691,65 @@ class ElectricalEnergyMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -329,6 +788,65 @@ class ElectricalEnergyMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -367,6 +885,63 @@ class ElectricalEnergyMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -405,6 +980,63 @@ class ElectricalEnergyMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -436,6 +1068,56 @@ class ElectricalEnergyMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -467,6 +1149,58 @@ class ElectricalEnergyMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ElectricalEnergyMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 145u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalMeasurementCluster.kt index de282984d4c67d..a44e1544733646 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ElectricalMeasurementCluster.kt @@ -20,11 +20,21 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.ByteSubscriptionState +import matter.controller.IntSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.ShortSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -42,12 +52,44 @@ class ElectricalMeasurementCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun getProfileInfoCommand(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -134,6 +176,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementtype attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcVoltageAttribute(): Short? { val ATTRIBUTE_ID: UInt = 256u @@ -170,6 +269,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 256u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dcvoltage attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcVoltageMinAttribute(): Short? { val ATTRIBUTE_ID: UInt = 257u @@ -206,6 +360,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcVoltageMinAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 257u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dcvoltagemin attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcVoltageMaxAttribute(): Short? { val ATTRIBUTE_ID: UInt = 258u @@ -242,6 +451,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcVoltageMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 258u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dcvoltagemax attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 259u @@ -278,6 +542,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 259u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dccurrent attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcCurrentMinAttribute(): Short? { val ATTRIBUTE_ID: UInt = 260u @@ -314,6 +633,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcCurrentMinAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 260u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dccurrentmin attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcCurrentMaxAttribute(): Short? { val ATTRIBUTE_ID: UInt = 261u @@ -350,6 +724,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcCurrentMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 261u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dccurrentmax attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcPowerAttribute(): Short? { val ATTRIBUTE_ID: UInt = 262u @@ -386,6 +815,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcPowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 262u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dcpower attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcPowerMinAttribute(): Short? { val ATTRIBUTE_ID: UInt = 263u @@ -422,6 +906,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcPowerMinAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 263u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dcpowermin attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcPowerMaxAttribute(): Short? { val ATTRIBUTE_ID: UInt = 264u @@ -458,6 +997,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcPowerMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 264u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dcpowermax attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcVoltageMultiplierAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 512u @@ -494,6 +1088,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcVoltageMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 512u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Dcvoltagemultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcVoltageDivisorAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 513u @@ -530,6 +1181,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcVoltageDivisorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 513u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Dcvoltagedivisor attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcCurrentMultiplierAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 514u @@ -566,6 +1274,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcCurrentMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 514u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Dccurrentmultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcCurrentDivisorAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 515u @@ -602,6 +1367,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcCurrentDivisorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 515u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Dccurrentdivisor attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcPowerMultiplierAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 516u @@ -638,6 +1460,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcPowerMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 516u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Dcpowermultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDcPowerDivisorAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 517u @@ -674,6 +1553,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeDcPowerDivisorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 517u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Dcpowerdivisor attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcFrequencyAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 768u @@ -710,15 +1646,70 @@ class ElectricalMeasurementCluster( return decodedValue } - suspend fun readAcFrequencyMinAttribute(): UShort? { - val ATTRIBUTE_ID: UInt = 769u - - val attributePath = - AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) - - val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + suspend fun subscribeAcFrequencyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 768u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) - val response = controller.read(readRequest) + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Acfrequency attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readAcFrequencyMinAttribute(): UShort? { + val ATTRIBUTE_ID: UInt = 769u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) if (response.successes.isEmpty()) { logger.log(Level.WARNING, "Read command failed") @@ -746,6 +1737,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcFrequencyMinAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 769u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acfrequencymin attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcFrequencyMaxAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 770u @@ -782,6 +1830,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcFrequencyMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 770u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acfrequencymax attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNeutralCurrentAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 771u @@ -818,6 +1923,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeNeutralCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 771u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Neutralcurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTotalActivePowerAttribute(): Int? { val ATTRIBUTE_ID: UInt = 772u @@ -854,6 +2016,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeTotalActivePowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 772u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + IntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Totalactivepower attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Int? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(IntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(IntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTotalReactivePowerAttribute(): Int? { val ATTRIBUTE_ID: UInt = 773u @@ -890,6 +2109,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeTotalReactivePowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 773u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + IntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Totalreactivepower attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Int? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(IntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(IntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTotalApparentPowerAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 774u @@ -926,6 +2202,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeTotalApparentPowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 774u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Totalapparentpower attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasured1stHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 775u @@ -962,6 +2295,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasured1stHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 775u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measured1stharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasured3rdHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 776u @@ -998,6 +2388,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasured3rdHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 776u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measured3rdharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasured5thHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 777u @@ -1034,6 +2481,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasured5thHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 777u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measured5thharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasured7thHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 778u @@ -1070,6 +2574,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasured7thHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 778u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measured7thharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasured9thHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 779u @@ -1106,6 +2667,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasured9thHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 779u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measured9thharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasured11thHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 780u @@ -1142,6 +2760,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasured11thHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 780u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measured11thharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasuredPhase1stHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 781u @@ -1180,6 +2855,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasuredPhase1stHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 781u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measuredphase1stharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasuredPhase3rdHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 782u @@ -1218,6 +2950,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasuredPhase3rdHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 782u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measuredphase3rdharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasuredPhase5thHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 783u @@ -1256,6 +3045,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasuredPhase5thHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 783u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measuredphase5thharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasuredPhase7thHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 784u @@ -1294,6 +3140,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasuredPhase7thHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 784u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measuredphase7thharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasuredPhase9thHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 785u @@ -1332,6 +3235,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasuredPhase9thHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 785u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measuredphase9thharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasuredPhase11thHarmonicCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 786u @@ -1370,6 +3330,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeMeasuredPhase11thHarmonicCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 786u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measuredphase11thharmoniccurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcFrequencyMultiplierAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1024u @@ -1406,6 +3423,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcFrequencyMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1024u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acfrequencymultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcFrequencyDivisorAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1025u @@ -1428,18 +3502,75 @@ class ElectricalMeasurementCluster( it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { "Acfrequencydivisor attribute not found in response" } + requireNotNull(attributeData) { "Acfrequencydivisor attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + return decodedValue + } + + suspend fun subscribeAcFrequencyDivisorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1025u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acfrequencydivisor attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } - // Decode the TLV data into the appropriate type - val tlvReader = TlvReader(attributeData.data) - val decodedValue: UShort? = - if (tlvReader.isNextTag(AnonymousTag)) { - tlvReader.getUShort(AnonymousTag) - } else { - null + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } } - - return decodedValue + } } suspend fun readPowerMultiplierAttribute(): UInt? { @@ -1478,6 +3609,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribePowerMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1026u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Powermultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPowerDivisorAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 1027u @@ -1514,6 +3702,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribePowerDivisorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1027u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Powerdivisor attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readHarmonicCurrentMultiplierAttribute(): Byte? { val ATTRIBUTE_ID: UInt = 1028u @@ -1550,6 +3793,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeHarmonicCurrentMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1028u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Harmoniccurrentmultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPhaseHarmonicCurrentMultiplierAttribute(): Byte? { val ATTRIBUTE_ID: UInt = 1029u @@ -1588,6 +3888,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribePhaseHarmonicCurrentMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1029u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Phaseharmoniccurrentmultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInstantaneousVoltageAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1280u @@ -1624,6 +3981,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeInstantaneousVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1280u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Instantaneousvoltage attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInstantaneousLineCurrentAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1281u @@ -1660,6 +4074,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeInstantaneousLineCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1281u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Instantaneouslinecurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInstantaneousActiveCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1282u @@ -1696,6 +4167,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeInstantaneousActiveCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1282u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Instantaneousactivecurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInstantaneousReactiveCurrentAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1283u @@ -1732,6 +4260,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeInstantaneousReactiveCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1283u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Instantaneousreactivecurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInstantaneousPowerAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1284u @@ -1768,6 +4353,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeInstantaneousPowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1284u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Instantaneouspower attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1285u @@ -1804,6 +4446,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1285u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rmsvoltage attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageMinAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1286u @@ -1840,6 +4537,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageMinAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1286u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rmsvoltagemin attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageMaxAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1287u @@ -1876,6 +4628,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1287u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rmsvoltagemax attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsCurrentAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1288u @@ -1912,6 +4719,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1288u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rmscurrent attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsCurrentMinAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1289u @@ -1948,6 +4810,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsCurrentMinAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1289u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rmscurrentmin attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsCurrentMaxAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1290u @@ -1984,6 +4901,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsCurrentMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1290u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rmscurrentmax attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActivePowerAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1291u @@ -2020,6 +4992,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeActivePowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1291u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Activepower attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActivePowerMinAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1292u @@ -2053,7 +5080,64 @@ class ElectricalMeasurementCluster( null } - return decodedValue + return decodedValue + } + + suspend fun subscribeActivePowerMinAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1292u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activepowermin attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } } suspend fun readActivePowerMaxAttribute(): Short? { @@ -2092,6 +5176,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeActivePowerMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1293u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activepowermax attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readReactivePowerAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1294u @@ -2128,6 +5269,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeReactivePowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1294u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Reactivepower attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readApparentPowerAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1295u @@ -2164,6 +5360,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeApparentPowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1295u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Apparentpower attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPowerFactorAttribute(): Byte? { val ATTRIBUTE_ID: UInt = 1296u @@ -2200,6 +5451,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribePowerFactorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1296u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Powerfactor attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsVoltageMeasurementPeriodAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1297u @@ -2281,6 +5587,63 @@ class ElectricalMeasurementCluster( } } + suspend fun subscribeAverageRmsVoltageMeasurementPeriodAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1297u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsvoltagemeasurementperiod attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsUnderVoltageCounterAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1299u @@ -2362,6 +5725,63 @@ class ElectricalMeasurementCluster( } } + suspend fun subscribeAverageRmsUnderVoltageCounterAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1299u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsundervoltagecounter attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsExtremeOverVoltagePeriodAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1300u @@ -2441,6 +5861,63 @@ class ElectricalMeasurementCluster( } } + suspend fun subscribeRmsExtremeOverVoltagePeriodAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1300u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsextremeovervoltageperiod attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsExtremeUnderVoltagePeriodAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1301u @@ -2520,6 +5997,63 @@ class ElectricalMeasurementCluster( } } + suspend fun subscribeRmsExtremeUnderVoltagePeriodAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1301u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsextremeundervoltageperiod attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageSagPeriodAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1302u @@ -2599,6 +6133,63 @@ class ElectricalMeasurementCluster( } } + suspend fun subscribeRmsVoltageSagPeriodAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1302u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltagesagperiod attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageSwellPeriodAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1303u @@ -2678,6 +6269,63 @@ class ElectricalMeasurementCluster( } } + suspend fun subscribeRmsVoltageSwellPeriodAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1303u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltageswellperiod attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcVoltageMultiplierAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1536u @@ -2714,6 +6362,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcVoltageMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1536u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acvoltagemultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcVoltageDivisorAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1537u @@ -2750,6 +6455,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcVoltageDivisorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1537u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acvoltagedivisor attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcCurrentMultiplierAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1538u @@ -2786,6 +6548,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcCurrentMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1538u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Accurrentmultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcCurrentDivisorAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1539u @@ -2822,6 +6641,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcCurrentDivisorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1539u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Accurrentdivisor attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcPowerMultiplierAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1540u @@ -2858,6 +6734,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcPowerMultiplierAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1540u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acpowermultiplier attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcPowerDivisorAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1541u @@ -2890,8 +6823,65 @@ class ElectricalMeasurementCluster( } else { null } - - return decodedValue + + return decodedValue + } + + suspend fun subscribeAcPowerDivisorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1541u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acpowerdivisor attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } } suspend fun readOverloadAlarmsMaskAttribute(): UByte? { @@ -2970,6 +6960,63 @@ class ElectricalMeasurementCluster( } } + suspend fun subscribeOverloadAlarmsMaskAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1792u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Overloadalarmsmask attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readVoltageOverloadAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1793u @@ -3006,6 +7053,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeVoltageOverloadAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1793u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Voltageoverload attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentOverloadAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1794u @@ -3042,6 +7146,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeCurrentOverloadAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1794u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentoverload attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcOverloadAlarmsMaskAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2048u @@ -3121,6 +7282,63 @@ class ElectricalMeasurementCluster( } } + suspend fun subscribeAcOverloadAlarmsMaskAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2048u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acoverloadalarmsmask attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcVoltageOverloadAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2049u @@ -3157,6 +7375,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcVoltageOverloadAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2049u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acvoltageoverload attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcCurrentOverloadAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2050u @@ -3193,6 +7468,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcCurrentOverloadAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2050u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Accurrentoverload attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcActivePowerOverloadAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2051u @@ -3229,6 +7561,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcActivePowerOverloadAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2051u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acactivepoweroverload attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcReactivePowerOverloadAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2052u @@ -3265,6 +7654,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAcReactivePowerOverloadAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2052u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acreactivepoweroverload attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsOverVoltageAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2053u @@ -3301,6 +7747,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAverageRmsOverVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2053u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsovervoltage attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsUnderVoltageAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2054u @@ -3337,6 +7840,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAverageRmsUnderVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2054u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsundervoltage attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsExtremeOverVoltageAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2055u @@ -3373,6 +7933,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsExtremeOverVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2055u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsextremeovervoltage attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsExtremeUnderVoltageAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2056u @@ -3409,6 +8026,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsExtremeUnderVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2056u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsextremeundervoltage attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageSagAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2057u @@ -3445,6 +8119,61 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageSagAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2057u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rmsvoltagesag attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageSwellAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2058u @@ -3481,6 +8210,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageSwellAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2058u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltageswell attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLineCurrentPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2305u @@ -3517,6 +8303,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeLineCurrentPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2305u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Linecurrentphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveCurrentPhaseBAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2306u @@ -3549,8 +8392,65 @@ class ElectricalMeasurementCluster( } else { null } - - return decodedValue + + return decodedValue + } + + suspend fun subscribeActiveCurrentPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2306u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activecurrentphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } } suspend fun readReactiveCurrentPhaseBAttribute(): Short? { @@ -3589,6 +8489,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeReactiveCurrentPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2307u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Reactivecurrentphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltagePhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2309u @@ -3625,6 +8582,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltagePhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2309u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltagephaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageMinPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2310u @@ -3661,6 +8675,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageMinPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2310u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltageminphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageMaxPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2311u @@ -3697,6 +8768,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageMaxPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2311u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltagemaxphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsCurrentPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2312u @@ -3733,6 +8861,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsCurrentPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2312u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmscurrentphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsCurrentMinPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2313u @@ -3769,6 +8954,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsCurrentMinPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2313u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmscurrentminphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsCurrentMaxPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2314u @@ -3805,6 +9047,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsCurrentMaxPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2314u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmscurrentmaxphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActivePowerPhaseBAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2315u @@ -3841,6 +9140,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeActivePowerPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2315u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activepowerphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActivePowerMinPhaseBAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2316u @@ -3877,6 +9233,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeActivePowerMinPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2316u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activepowerminphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActivePowerMaxPhaseBAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2317u @@ -3913,6 +9326,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeActivePowerMaxPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2317u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activepowermaxphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readReactivePowerPhaseBAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2318u @@ -3949,6 +9419,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeReactivePowerPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2318u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Reactivepowerphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readApparentPowerPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2319u @@ -3985,6 +9512,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeApparentPowerPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2319u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Apparentpowerphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPowerFactorPhaseBAttribute(): Byte? { val ATTRIBUTE_ID: UInt = 2320u @@ -4021,6 +9605,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribePowerFactorPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2320u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Powerfactorphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsVoltageMeasurementPeriodPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2321u @@ -4059,6 +9700,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAverageRmsVoltageMeasurementPeriodPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2321u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsvoltagemeasurementperiodphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsOverVoltageCounterPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2322u @@ -4097,6 +9795,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAverageRmsOverVoltageCounterPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2322u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsovervoltagecounterphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsUnderVoltageCounterPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2323u @@ -4132,7 +9887,64 @@ class ElectricalMeasurementCluster( null } - return decodedValue + return decodedValue + } + + suspend fun subscribeAverageRmsUnderVoltageCounterPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2323u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsundervoltagecounterphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } } suspend fun readRmsExtremeOverVoltagePeriodPhaseBAttribute(): UShort? { @@ -4173,6 +9985,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsExtremeOverVoltagePeriodPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2324u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsextremeovervoltageperiodphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsExtremeUnderVoltagePeriodPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2325u @@ -4211,6 +10080,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsExtremeUnderVoltagePeriodPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2325u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsextremeundervoltageperiodphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageSagPeriodPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2326u @@ -4247,6 +10173,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageSagPeriodPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2326u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltagesagperiodphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageSwellPeriodPhaseBAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2327u @@ -4283,6 +10266,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageSwellPeriodPhaseBAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2327u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltageswellperiodphaseb attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLineCurrentPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2561u @@ -4319,6 +10359,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeLineCurrentPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2561u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Linecurrentphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveCurrentPhaseCAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2562u @@ -4355,6 +10452,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeActiveCurrentPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2562u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activecurrentphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readReactiveCurrentPhaseCAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2563u @@ -4391,6 +10545,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeReactiveCurrentPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2563u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Reactivecurrentphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltagePhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2565u @@ -4427,6 +10638,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltagePhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2565u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltagephasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageMinPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2566u @@ -4463,6 +10731,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageMinPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2566u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltageminphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageMaxPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2567u @@ -4499,6 +10824,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageMaxPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2567u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltagemaxphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsCurrentPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2568u @@ -4535,6 +10917,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsCurrentPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2568u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmscurrentphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsCurrentMinPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2569u @@ -4571,6 +11010,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsCurrentMinPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2569u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmscurrentminphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsCurrentMaxPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2570u @@ -4607,6 +11103,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsCurrentMaxPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2570u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmscurrentmaxphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActivePowerPhaseCAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2571u @@ -4643,6 +11196,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeActivePowerPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2571u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activepowerphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActivePowerMinPhaseCAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2572u @@ -4679,6 +11289,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeActivePowerMinPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2572u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activepowerminphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActivePowerMaxPhaseCAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2573u @@ -4712,7 +11379,64 @@ class ElectricalMeasurementCluster( null } - return decodedValue + return decodedValue + } + + suspend fun subscribeActivePowerMaxPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2573u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activepowermaxphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } } suspend fun readReactivePowerPhaseCAttribute(): Short? { @@ -4751,6 +11475,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeReactivePowerPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2574u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Reactivepowerphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readApparentPowerPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2575u @@ -4787,6 +11568,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeApparentPowerPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2575u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Apparentpowerphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPowerFactorPhaseCAttribute(): Byte? { val ATTRIBUTE_ID: UInt = 2576u @@ -4823,6 +11661,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribePowerFactorPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2576u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Powerfactorphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsVoltageMeasurementPeriodPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2577u @@ -4861,6 +11756,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAverageRmsVoltageMeasurementPeriodPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2577u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsvoltagemeasurementperiodphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsOverVoltageCounterPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2578u @@ -4899,6 +11851,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAverageRmsOverVoltageCounterPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2578u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsovervoltagecounterphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageRmsUnderVoltageCounterPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2579u @@ -4937,6 +11946,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeAverageRmsUnderVoltageCounterPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2579u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagermsundervoltagecounterphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsExtremeOverVoltagePeriodPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2580u @@ -4975,6 +12041,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsExtremeOverVoltagePeriodPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2580u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsextremeovervoltageperiodphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsExtremeUnderVoltagePeriodPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2581u @@ -5013,6 +12136,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsExtremeUnderVoltagePeriodPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2581u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsextremeundervoltageperiodphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageSagPeriodPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2582u @@ -5049,6 +12229,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageSagPeriodPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2582u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltagesagperiodphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRmsVoltageSwellPeriodPhaseCAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2583u @@ -5085,6 +12322,63 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeRmsVoltageSwellPeriodPhaseCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2583u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rmsvoltageswellperiodphasec attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -5123,6 +12417,65 @@ class ElectricalMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -5161,6 +12514,65 @@ class ElectricalMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -5199,6 +12611,63 @@ class ElectricalMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -5237,6 +12706,63 @@ class ElectricalMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -5268,6 +12794,56 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -5299,6 +12875,58 @@ class ElectricalMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ElectricalMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 2820u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/EnergyEvseCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/EnergyEvseCluster.kt index 615839a2191b26..c2a269e96018af 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/EnergyEvseCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/EnergyEvseCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse +import matter.controller.LongSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -44,42 +52,198 @@ class EnergyEvseCluster(private val controller: MatterController, private val en class StateAttribute(val value: UByte?) + sealed class StateAttributeSubscriptionState { + data class Success(val value: UByte?) : StateAttributeSubscriptionState() + + data class Error(val exception: Exception) : StateAttributeSubscriptionState() + + object SubscriptionEstablished : StateAttributeSubscriptionState() + } + class ChargingEnabledUntilAttribute(val value: UInt?) + sealed class ChargingEnabledUntilAttributeSubscriptionState { + data class Success(val value: UInt?) : ChargingEnabledUntilAttributeSubscriptionState() + + data class Error(val exception: Exception) : ChargingEnabledUntilAttributeSubscriptionState() + + object SubscriptionEstablished : ChargingEnabledUntilAttributeSubscriptionState() + } + class DischargingEnabledUntilAttribute(val value: UInt?) + sealed class DischargingEnabledUntilAttributeSubscriptionState { + data class Success(val value: UInt?) : DischargingEnabledUntilAttributeSubscriptionState() + + data class Error(val exception: Exception) : + DischargingEnabledUntilAttributeSubscriptionState() + + object SubscriptionEstablished : DischargingEnabledUntilAttributeSubscriptionState() + } + class NextChargeStartTimeAttribute(val value: UInt?) + sealed class NextChargeStartTimeAttributeSubscriptionState { + data class Success(val value: UInt?) : NextChargeStartTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : NextChargeStartTimeAttributeSubscriptionState() + + object SubscriptionEstablished : NextChargeStartTimeAttributeSubscriptionState() + } + class NextChargeTargetTimeAttribute(val value: UInt?) + sealed class NextChargeTargetTimeAttributeSubscriptionState { + data class Success(val value: UInt?) : NextChargeTargetTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : NextChargeTargetTimeAttributeSubscriptionState() + + object SubscriptionEstablished : NextChargeTargetTimeAttributeSubscriptionState() + } + class NextChargeRequiredEnergyAttribute(val value: Long?) + sealed class NextChargeRequiredEnergyAttributeSubscriptionState { + data class Success(val value: Long?) : NextChargeRequiredEnergyAttributeSubscriptionState() + + data class Error(val exception: Exception) : + NextChargeRequiredEnergyAttributeSubscriptionState() + + object SubscriptionEstablished : NextChargeRequiredEnergyAttributeSubscriptionState() + } + class NextChargeTargetSoCAttribute(val value: UByte?) + sealed class NextChargeTargetSoCAttributeSubscriptionState { + data class Success(val value: UByte?) : NextChargeTargetSoCAttributeSubscriptionState() + + data class Error(val exception: Exception) : NextChargeTargetSoCAttributeSubscriptionState() + + object SubscriptionEstablished : NextChargeTargetSoCAttributeSubscriptionState() + } + class ApproximateEVEfficiencyAttribute(val value: UShort?) + sealed class ApproximateEVEfficiencyAttributeSubscriptionState { + data class Success(val value: UShort?) : ApproximateEVEfficiencyAttributeSubscriptionState() + + data class Error(val exception: Exception) : + ApproximateEVEfficiencyAttributeSubscriptionState() + + object SubscriptionEstablished : ApproximateEVEfficiencyAttributeSubscriptionState() + } + class StateOfChargeAttribute(val value: UByte?) + sealed class StateOfChargeAttributeSubscriptionState { + data class Success(val value: UByte?) : StateOfChargeAttributeSubscriptionState() + + data class Error(val exception: Exception) : StateOfChargeAttributeSubscriptionState() + + object SubscriptionEstablished : StateOfChargeAttributeSubscriptionState() + } + class BatteryCapacityAttribute(val value: Long?) + sealed class BatteryCapacityAttributeSubscriptionState { + data class Success(val value: Long?) : BatteryCapacityAttributeSubscriptionState() + + data class Error(val exception: Exception) : BatteryCapacityAttributeSubscriptionState() + + object SubscriptionEstablished : BatteryCapacityAttributeSubscriptionState() + } + class VehicleIDAttribute(val value: String?) + sealed class VehicleIDAttributeSubscriptionState { + data class Success(val value: String?) : VehicleIDAttributeSubscriptionState() + + data class Error(val exception: Exception) : VehicleIDAttributeSubscriptionState() + + object SubscriptionEstablished : VehicleIDAttributeSubscriptionState() + } + class SessionIDAttribute(val value: UInt?) + sealed class SessionIDAttributeSubscriptionState { + data class Success(val value: UInt?) : SessionIDAttributeSubscriptionState() + + data class Error(val exception: Exception) : SessionIDAttributeSubscriptionState() + + object SubscriptionEstablished : SessionIDAttributeSubscriptionState() + } + class SessionDurationAttribute(val value: UInt?) + sealed class SessionDurationAttributeSubscriptionState { + data class Success(val value: UInt?) : SessionDurationAttributeSubscriptionState() + + data class Error(val exception: Exception) : SessionDurationAttributeSubscriptionState() + + object SubscriptionEstablished : SessionDurationAttributeSubscriptionState() + } + class SessionEnergyChargedAttribute(val value: Long?) + sealed class SessionEnergyChargedAttributeSubscriptionState { + data class Success(val value: Long?) : SessionEnergyChargedAttributeSubscriptionState() + + data class Error(val exception: Exception) : SessionEnergyChargedAttributeSubscriptionState() + + object SubscriptionEstablished : SessionEnergyChargedAttributeSubscriptionState() + } + class SessionEnergyDischargedAttribute(val value: Long?) + sealed class SessionEnergyDischargedAttributeSubscriptionState { + data class Success(val value: Long?) : SessionEnergyDischargedAttributeSubscriptionState() + + data class Error(val exception: Exception) : + SessionEnergyDischargedAttributeSubscriptionState() + + object SubscriptionEstablished : SessionEnergyDischargedAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun disable(timedInvokeTimeout: Duration) { val commandId: UInt = 1u @@ -329,6 +493,62 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return StateAttribute(decodedValue) } + suspend fun subscribeStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StateAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "State attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StateAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StateAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupplyStateAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -360,6 +580,56 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeSupplyStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Supplystate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFaultStateAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -391,6 +661,56 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFaultStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Faultstate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readChargingEnabledUntilAttribute(): ChargingEnabledUntilAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -428,6 +748,64 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return ChargingEnabledUntilAttribute(decodedValue) } + suspend fun subscribeChargingEnabledUntilAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ChargingEnabledUntilAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Chargingenableduntil attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + tlvReader.getUInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ChargingEnabledUntilAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ChargingEnabledUntilAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDischargingEnabledUntilAttribute(): DischargingEnabledUntilAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -469,6 +847,68 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return DischargingEnabledUntilAttribute(decodedValue) } + suspend fun subscribeDischargingEnabledUntilAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DischargingEnabledUntilAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Dischargingenableduntil attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(DischargingEnabledUntilAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(DischargingEnabledUntilAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCircuitCapacityAttribute(): Long { val ATTRIBUTE_ID: UInt = 5u @@ -500,6 +940,58 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeCircuitCapacityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Circuitcapacity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long = tlvReader.getLong(AnonymousTag) + + emit(LongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinimumChargeCurrentAttribute(): Long { val ATTRIBUTE_ID: UInt = 6u @@ -531,6 +1023,58 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeMinimumChargeCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minimumchargecurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long = tlvReader.getLong(AnonymousTag) + + emit(LongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaximumChargeCurrentAttribute(): Long { val ATTRIBUTE_ID: UInt = 7u @@ -562,6 +1106,58 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeMaximumChargeCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maximumchargecurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long = tlvReader.getLong(AnonymousTag) + + emit(LongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaximumDischargeCurrentAttribute(): Long? { val ATTRIBUTE_ID: UInt = 8u @@ -598,6 +1194,63 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeMaximumDischargeCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maximumdischargecurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getLong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(LongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUserMaximumChargeCurrentAttribute(): Long? { val ATTRIBUTE_ID: UInt = 9u @@ -677,6 +1330,63 @@ class EnergyEvseCluster(private val controller: MatterController, private val en } } + suspend fun subscribeUserMaximumChargeCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Usermaximumchargecurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getLong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(LongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRandomizationDelayWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 10u @@ -756,6 +1466,63 @@ class EnergyEvseCluster(private val controller: MatterController, private val en } } + suspend fun subscribeRandomizationDelayWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Randomizationdelaywindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfWeeklyTargetsAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 33u @@ -792,6 +1559,63 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeNumberOfWeeklyTargetsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 33u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofweeklytargets attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfDailyTargetsAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 34u @@ -828,6 +1652,63 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeNumberOfDailyTargetsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 34u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofdailytargets attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNextChargeStartTimeAttribute(): NextChargeStartTimeAttribute { val ATTRIBUTE_ID: UInt = 35u @@ -869,6 +1750,68 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return NextChargeStartTimeAttribute(decodedValue) } + suspend fun subscribeNextChargeStartTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 35u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NextChargeStartTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nextchargestarttime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NextChargeStartTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NextChargeStartTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNextChargeTargetTimeAttribute(): NextChargeTargetTimeAttribute { val ATTRIBUTE_ID: UInt = 36u @@ -910,6 +1853,68 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return NextChargeTargetTimeAttribute(decodedValue) } + suspend fun subscribeNextChargeTargetTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 36u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NextChargeTargetTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nextchargetargettime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NextChargeTargetTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NextChargeTargetTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNextChargeRequiredEnergyAttribute(): NextChargeRequiredEnergyAttribute { val ATTRIBUTE_ID: UInt = 37u @@ -951,6 +1956,68 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return NextChargeRequiredEnergyAttribute(decodedValue) } + suspend fun subscribeNextChargeRequiredEnergyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 37u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NextChargeRequiredEnergyAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nextchargerequiredenergy attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getLong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NextChargeRequiredEnergyAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NextChargeRequiredEnergyAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNextChargeTargetSoCAttribute(): NextChargeTargetSoCAttribute { val ATTRIBUTE_ID: UInt = 38u @@ -992,6 +2059,68 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return NextChargeTargetSoCAttribute(decodedValue) } + suspend fun subscribeNextChargeTargetSoCAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 38u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NextChargeTargetSoCAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nextchargetargetsoc attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NextChargeTargetSoCAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NextChargeTargetSoCAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readApproximateEVEfficiencyAttribute(): ApproximateEVEfficiencyAttribute { val ATTRIBUTE_ID: UInt = 39u @@ -1076,6 +2205,68 @@ class EnergyEvseCluster(private val controller: MatterController, private val en } } + suspend fun subscribeApproximateEVEfficiencyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 39u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ApproximateEVEfficiencyAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Approximateevefficiency attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ApproximateEVEfficiencyAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ApproximateEVEfficiencyAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStateOfChargeAttribute(): StateOfChargeAttribute { val ATTRIBUTE_ID: UInt = 48u @@ -1117,6 +2308,66 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return StateOfChargeAttribute(decodedValue) } + suspend fun subscribeStateOfChargeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 48u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StateOfChargeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Stateofcharge attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StateOfChargeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StateOfChargeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatteryCapacityAttribute(): BatteryCapacityAttribute { val ATTRIBUTE_ID: UInt = 49u @@ -1158,6 +2409,68 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return BatteryCapacityAttribute(decodedValue) } + suspend fun subscribeBatteryCapacityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 49u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BatteryCapacityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batterycapacity attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getLong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BatteryCapacityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BatteryCapacityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readVehicleIDAttribute(): VehicleIDAttribute { val ATTRIBUTE_ID: UInt = 50u @@ -1199,6 +2512,66 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return VehicleIDAttribute(decodedValue) } + suspend fun subscribeVehicleIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 50u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + VehicleIDAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Vehicleid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(VehicleIDAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(VehicleIDAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSessionIDAttribute(): SessionIDAttribute { val ATTRIBUTE_ID: UInt = 64u @@ -1236,6 +2609,62 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return SessionIDAttribute(decodedValue) } + suspend fun subscribeSessionIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 64u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SessionIDAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Sessionid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + tlvReader.getUInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SessionIDAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SessionIDAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSessionDurationAttribute(): SessionDurationAttribute { val ATTRIBUTE_ID: UInt = 65u @@ -1273,6 +2702,64 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return SessionDurationAttribute(decodedValue) } + suspend fun subscribeSessionDurationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SessionDurationAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Sessionduration attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + tlvReader.getUInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SessionDurationAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SessionDurationAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSessionEnergyChargedAttribute(): SessionEnergyChargedAttribute { val ATTRIBUTE_ID: UInt = 66u @@ -1310,6 +2797,64 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return SessionEnergyChargedAttribute(decodedValue) } + suspend fun subscribeSessionEnergyChargedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 66u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SessionEnergyChargedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Sessionenergycharged attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (!tlvReader.isNull()) { + tlvReader.getLong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SessionEnergyChargedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SessionEnergyChargedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSessionEnergyDischargedAttribute(): SessionEnergyDischargedAttribute { val ATTRIBUTE_ID: UInt = 67u @@ -1351,6 +2896,68 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return SessionEnergyDischargedAttribute(decodedValue) } + suspend fun subscribeSessionEnergyDischargedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 67u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SessionEnergyDischargedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Sessionenergydischarged attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getLong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SessionEnergyDischargedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SessionEnergyDischargedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1389,6 +2996,65 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1427,6 +3093,65 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1465,6 +3190,63 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1503,6 +3285,63 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1534,6 +3373,56 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1565,6 +3454,58 @@ class EnergyEvseCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(EnergyEvseCluster::class.java.name) const val CLUSTER_ID: UInt = 153u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/EthernetNetworkDiagnosticsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/EthernetNetworkDiagnosticsCluster.kt index 36d51a163da90a..42447fc0dc649a 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/EthernetNetworkDiagnosticsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/EthernetNetworkDiagnosticsCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.ULongSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -38,18 +45,74 @@ class EthernetNetworkDiagnosticsCluster( ) { class PHYRateAttribute(val value: UByte?) + sealed class PHYRateAttributeSubscriptionState { + data class Success(val value: UByte?) : PHYRateAttributeSubscriptionState() + + data class Error(val exception: Exception) : PHYRateAttributeSubscriptionState() + + object SubscriptionEstablished : PHYRateAttributeSubscriptionState() + } + class FullDuplexAttribute(val value: Boolean?) + sealed class FullDuplexAttributeSubscriptionState { + data class Success(val value: Boolean?) : FullDuplexAttributeSubscriptionState() + + data class Error(val exception: Exception) : FullDuplexAttributeSubscriptionState() + + object SubscriptionEstablished : FullDuplexAttributeSubscriptionState() + } + class CarrierDetectAttribute(val value: Boolean?) + sealed class CarrierDetectAttributeSubscriptionState { + data class Success(val value: Boolean?) : CarrierDetectAttributeSubscriptionState() + + data class Error(val exception: Exception) : CarrierDetectAttributeSubscriptionState() + + object SubscriptionEstablished : CarrierDetectAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun resetCounts(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -109,6 +172,66 @@ class EthernetNetworkDiagnosticsCluster( return PHYRateAttribute(decodedValue) } + suspend fun subscribePHYRateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PHYRateAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Phyrate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PHYRateAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PHYRateAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFullDuplexAttribute(): FullDuplexAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -150,6 +273,66 @@ class EthernetNetworkDiagnosticsCluster( return FullDuplexAttribute(decodedValue) } + suspend fun subscribeFullDuplexAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FullDuplexAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Fullduplex attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(FullDuplexAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FullDuplexAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPacketRxCountAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 2u @@ -186,6 +369,61 @@ class EthernetNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribePacketRxCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Packetrxcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPacketTxCountAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 3u @@ -222,6 +460,61 @@ class EthernetNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribePacketTxCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Packettxcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxErrCountAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 4u @@ -258,6 +551,61 @@ class EthernetNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxErrCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Txerrcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCollisionCountAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 5u @@ -294,6 +642,63 @@ class EthernetNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeCollisionCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Collisioncount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOverrunCountAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 6u @@ -330,6 +735,61 @@ class EthernetNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeOverrunCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Overruncount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCarrierDetectAttribute(): CarrierDetectAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -371,6 +831,66 @@ class EthernetNetworkDiagnosticsCluster( return CarrierDetectAttribute(decodedValue) } + suspend fun subscribeCarrierDetectAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CarrierDetectAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Carrierdetect attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CarrierDetectAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CarrierDetectAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTimeSinceResetAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 8u @@ -407,6 +927,63 @@ class EthernetNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTimeSinceResetAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Timesincereset attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -445,6 +1022,65 @@ class EthernetNetworkDiagnosticsCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -483,6 +1119,65 @@ class EthernetNetworkDiagnosticsCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -521,6 +1216,63 @@ class EthernetNetworkDiagnosticsCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -559,6 +1311,63 @@ class EthernetNetworkDiagnosticsCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -590,6 +1399,56 @@ class EthernetNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -621,6 +1480,58 @@ class EthernetNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(EthernetNetworkDiagnosticsCluster::class.java.name) const val CLUSTER_ID: UInt = 55u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/FanControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/FanControlCluster.kt index 9d82a42242442d..12baa895406dac 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/FanControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/FanControlCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -39,16 +46,64 @@ import matter.tlv.TlvWriter class FanControlCluster(private val controller: MatterController, private val endpointId: UShort) { class PercentSettingAttribute(val value: UByte?) + sealed class PercentSettingAttributeSubscriptionState { + data class Success(val value: UByte?) : PercentSettingAttributeSubscriptionState() + + data class Error(val exception: Exception) : PercentSettingAttributeSubscriptionState() + + object SubscriptionEstablished : PercentSettingAttributeSubscriptionState() + } + class SpeedSettingAttribute(val value: UByte?) + sealed class SpeedSettingAttributeSubscriptionState { + data class Success(val value: UByte?) : SpeedSettingAttributeSubscriptionState() + + data class Error(val exception: Exception) : SpeedSettingAttributeSubscriptionState() + + object SubscriptionEstablished : SpeedSettingAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun step( direction: UByte, wrap: Boolean?, @@ -152,6 +207,56 @@ class FanControlCluster(private val controller: MatterController, private val en } } + suspend fun subscribeFanModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Fanmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFanModeSequenceAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -183,6 +288,58 @@ class FanControlCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFanModeSequenceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Fanmodesequence attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPercentSettingAttribute(): PercentSettingAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -260,6 +417,64 @@ class FanControlCluster(private val controller: MatterController, private val en } } + suspend fun subscribePercentSettingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PercentSettingAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Percentsetting attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PercentSettingAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PercentSettingAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPercentCurrentAttribute(): UByte { val ATTRIBUTE_ID: UInt = 3u @@ -291,6 +506,58 @@ class FanControlCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribePercentCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Percentcurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSpeedMaxAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 4u @@ -327,6 +594,61 @@ class FanControlCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeSpeedMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Speedmax attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSpeedSettingAttribute(): SpeedSettingAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -408,6 +730,66 @@ class FanControlCluster(private val controller: MatterController, private val en } } + suspend fun subscribeSpeedSettingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SpeedSettingAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Speedsetting attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SpeedSettingAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SpeedSettingAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSpeedCurrentAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 6u @@ -444,6 +826,61 @@ class FanControlCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeSpeedCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Speedcurrent attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRockSupportAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 7u @@ -480,6 +917,61 @@ class FanControlCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeRockSupportAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rocksupport attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRockSettingAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -556,6 +1048,61 @@ class FanControlCluster(private val controller: MatterController, private val en } } + suspend fun subscribeRockSettingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rocksetting attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWindSupportAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -592,6 +1139,61 @@ class FanControlCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeWindSupportAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Windsupport attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWindSettingAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -668,6 +1270,61 @@ class FanControlCluster(private val controller: MatterController, private val en } } + suspend fun subscribeWindSettingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Windsetting attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAirflowDirectionAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 11u @@ -744,6 +1401,63 @@ class FanControlCluster(private val controller: MatterController, private val en } } + suspend fun subscribeAirflowDirectionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Airflowdirection attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -782,6 +1496,65 @@ class FanControlCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -820,6 +1593,65 @@ class FanControlCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -858,6 +1690,63 @@ class FanControlCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -896,6 +1785,63 @@ class FanControlCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -927,6 +1873,56 @@ class FanControlCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -958,6 +1954,58 @@ class FanControlCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(FanControlCluster::class.java.name) const val CLUSTER_ID: UInt = 514u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/FaultInjectionCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/FaultInjectionCluster.kt index 7d40a448831930..5597bfd94af98a 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/FaultInjectionCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/FaultInjectionCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -39,12 +45,44 @@ class FaultInjectionCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun failAtFault( type: UByte, id: UInt, @@ -155,6 +193,65 @@ class FaultInjectionCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -193,6 +290,65 @@ class FaultInjectionCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -231,6 +387,63 @@ class FaultInjectionCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -269,6 +482,63 @@ class FaultInjectionCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -300,6 +570,56 @@ class FaultInjectionCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -331,6 +651,58 @@ class FaultInjectionCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(FaultInjectionCluster::class.java.name) const val CLUSTER_ID: UInt = 4294048774u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/FixedLabelCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/FixedLabelCluster.kt index 6d6c8098a99767..4fe3dd45c9ccd6 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/FixedLabelCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/FixedLabelCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -30,14 +37,55 @@ import matter.tlv.TlvReader class FixedLabelCluster(private val controller: MatterController, private val endpointId: UShort) { class LabelListAttribute(val value: List) + sealed class LabelListAttributeSubscriptionState { + data class Success(val value: List) : + LabelListAttributeSubscriptionState() + + data class Error(val exception: Exception) : LabelListAttributeSubscriptionState() + + object SubscriptionEstablished : LabelListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readLabelListAttribute(): LabelListAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -76,6 +124,63 @@ class FixedLabelCluster(private val controller: MatterController, private val en return LabelListAttribute(decodedValue) } + suspend fun subscribeLabelListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LabelListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Labellist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(FixedLabelClusterLabelStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(LabelListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LabelListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -114,6 +219,65 @@ class FixedLabelCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -152,6 +316,65 @@ class FixedLabelCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -190,6 +413,63 @@ class FixedLabelCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -228,6 +508,63 @@ class FixedLabelCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -259,6 +596,56 @@ class FixedLabelCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -290,6 +677,58 @@ class FixedLabelCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(FixedLabelCluster::class.java.name) const val CLUSTER_ID: UInt = 64u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/FlowMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/FlowMeasurementCluster.kt index 0f9c139f6dcd6e..35d293bd0a4ca9 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/FlowMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/FlowMeasurementCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,18 +40,74 @@ class FlowMeasurementCluster( ) { class MeasuredValueAttribute(val value: UShort?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: UShort?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: UShort?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: UShort?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: UShort?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: UShort?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -82,6 +145,62 @@ class FlowMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -119,6 +238,64 @@ class FlowMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -156,6 +333,64 @@ class FlowMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readToleranceAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 3u @@ -192,6 +427,61 @@ class FlowMeasurementCluster( return decodedValue } + suspend fun subscribeToleranceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Tolerance attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -230,6 +520,65 @@ class FlowMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -268,6 +617,65 @@ class FlowMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -306,6 +714,63 @@ class FlowMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -344,6 +809,63 @@ class FlowMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -375,6 +897,56 @@ class FlowMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -406,6 +978,58 @@ class FlowMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(FlowMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1028u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/FormaldehydeConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/FormaldehydeConcentrationMeasurementCluster.kt index ddcc4dedd812b7..c60f4e6484a856 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/FormaldehydeConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/FormaldehydeConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class FormaldehydeConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class FormaldehydeConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class FormaldehydeConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class FormaldehydeConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class FormaldehydeConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class FormaldehydeConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class FormaldehydeConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class FormaldehydeConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class FormaldehydeConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class FormaldehydeConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class FormaldehydeConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class FormaldehydeConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class FormaldehydeConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class FormaldehydeConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class FormaldehydeConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class FormaldehydeConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class FormaldehydeConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class FormaldehydeConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(FormaldehydeConcentrationMeasurementCluster::class.java.name) diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/GeneralCommissioningCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/GeneralCommissioningCluster.kt index 64dacf9319ef2c..f16803780a0253 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/GeneralCommissioningCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/GeneralCommissioningCluster.kt @@ -20,11 +20,20 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.ULongSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -50,14 +59,55 @@ class GeneralCommissioningCluster( val value: GeneralCommissioningClusterBasicCommissioningInfo ) + sealed class BasicCommissioningInfoAttributeSubscriptionState { + data class Success(val value: GeneralCommissioningClusterBasicCommissioningInfo) : + BasicCommissioningInfoAttributeSubscriptionState() + + data class Error(val exception: Exception) : BasicCommissioningInfoAttributeSubscriptionState() + + object SubscriptionEstablished : BasicCommissioningInfoAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun armFailSafe( expiryLengthSeconds: UShort, breadcrumb: ULong, @@ -311,6 +361,56 @@ class GeneralCommissioningCluster( } } + suspend fun subscribeBreadcrumbAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Breadcrumb attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong = tlvReader.getULong(AnonymousTag) + + emit(ULongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBasicCommissioningInfoAttribute(): BasicCommissioningInfoAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -343,6 +443,59 @@ class GeneralCommissioningCluster( return BasicCommissioningInfoAttribute(decodedValue) } + suspend fun subscribeBasicCommissioningInfoAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BasicCommissioningInfoAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Basiccommissioninginfo attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: GeneralCommissioningClusterBasicCommissioningInfo = + GeneralCommissioningClusterBasicCommissioningInfo.fromTlv(AnonymousTag, tlvReader) + + emit(BasicCommissioningInfoAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BasicCommissioningInfoAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRegulatoryConfigAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -374,6 +527,58 @@ class GeneralCommissioningCluster( return decodedValue } + suspend fun subscribeRegulatoryConfigAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Regulatoryconfig attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLocationCapabilityAttribute(): UByte { val ATTRIBUTE_ID: UInt = 3u @@ -405,6 +610,58 @@ class GeneralCommissioningCluster( return decodedValue } + suspend fun subscribeLocationCapabilityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Locationcapability attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportsConcurrentConnectionAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 4u @@ -436,6 +693,58 @@ class GeneralCommissioningCluster( return decodedValue } + suspend fun subscribeSupportsConcurrentConnectionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportsconcurrentconnection attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -474,6 +783,65 @@ class GeneralCommissioningCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -512,6 +880,65 @@ class GeneralCommissioningCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -550,6 +977,63 @@ class GeneralCommissioningCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -588,6 +1072,63 @@ class GeneralCommissioningCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -619,6 +1160,56 @@ class GeneralCommissioningCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -650,6 +1241,58 @@ class GeneralCommissioningCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(GeneralCommissioningCluster::class.java.name) const val CLUSTER_ID: UInt = 48u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/GeneralDiagnosticsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/GeneralDiagnosticsCluster.kt index bb27b9469a666f..cdc7a18ad10d15 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/GeneralDiagnosticsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/GeneralDiagnosticsCluster.kt @@ -20,11 +20,20 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.ULongSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,20 +50,85 @@ class GeneralDiagnosticsCluster( class NetworkInterfacesAttribute(val value: List) + sealed class NetworkInterfacesAttributeSubscriptionState { + data class Success(val value: List) : + NetworkInterfacesAttributeSubscriptionState() + + data class Error(val exception: Exception) : NetworkInterfacesAttributeSubscriptionState() + + object SubscriptionEstablished : NetworkInterfacesAttributeSubscriptionState() + } + class ActiveHardwareFaultsAttribute(val value: List?) + sealed class ActiveHardwareFaultsAttributeSubscriptionState { + data class Success(val value: List?) : ActiveHardwareFaultsAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveHardwareFaultsAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveHardwareFaultsAttributeSubscriptionState() + } + class ActiveRadioFaultsAttribute(val value: List?) + sealed class ActiveRadioFaultsAttributeSubscriptionState { + data class Success(val value: List?) : ActiveRadioFaultsAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveRadioFaultsAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveRadioFaultsAttributeSubscriptionState() + } + class ActiveNetworkFaultsAttribute(val value: List?) + sealed class ActiveNetworkFaultsAttributeSubscriptionState { + data class Success(val value: List?) : ActiveNetworkFaultsAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveNetworkFaultsAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveNetworkFaultsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun testEventTrigger( enableKey: ByteArray, eventTrigger: ULong, @@ -180,6 +254,65 @@ class GeneralDiagnosticsCluster( return NetworkInterfacesAttribute(decodedValue) } + suspend fun subscribeNetworkInterfacesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NetworkInterfacesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Networkinterfaces attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(GeneralDiagnosticsClusterNetworkInterface.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(NetworkInterfacesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(NetworkInterfacesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRebootCountAttribute(): UShort { val ATTRIBUTE_ID: UInt = 1u @@ -211,6 +344,56 @@ class GeneralDiagnosticsCluster( return decodedValue } + suspend fun subscribeRebootCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rebootcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUpTimeAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 2u @@ -247,6 +430,61 @@ class GeneralDiagnosticsCluster( return decodedValue } + suspend fun subscribeUpTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uptime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTotalOperationalHoursAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 3u @@ -283,6 +521,63 @@ class GeneralDiagnosticsCluster( return decodedValue } + suspend fun subscribeTotalOperationalHoursAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Totaloperationalhours attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBootReasonAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 4u @@ -319,6 +614,61 @@ class GeneralDiagnosticsCluster( return decodedValue } + suspend fun subscribeBootReasonAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Bootreason attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveHardwareFaultsAttribute(): ActiveHardwareFaultsAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -361,6 +711,69 @@ class GeneralDiagnosticsCluster( return ActiveHardwareFaultsAttribute(decodedValue) } + suspend fun subscribeActiveHardwareFaultsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveHardwareFaultsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activehardwarefaults attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ActiveHardwareFaultsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveHardwareFaultsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveRadioFaultsAttribute(): ActiveRadioFaultsAttribute { val ATTRIBUTE_ID: UInt = 6u @@ -403,6 +816,69 @@ class GeneralDiagnosticsCluster( return ActiveRadioFaultsAttribute(decodedValue) } + suspend fun subscribeActiveRadioFaultsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveRadioFaultsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activeradiofaults attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ActiveRadioFaultsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveRadioFaultsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveNetworkFaultsAttribute(): ActiveNetworkFaultsAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -445,6 +921,69 @@ class GeneralDiagnosticsCluster( return ActiveNetworkFaultsAttribute(decodedValue) } + suspend fun subscribeActiveNetworkFaultsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveNetworkFaultsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activenetworkfaults attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ActiveNetworkFaultsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveNetworkFaultsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTestEventTriggersEnabledAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 8u @@ -476,6 +1015,58 @@ class GeneralDiagnosticsCluster( return decodedValue } + suspend fun subscribeTestEventTriggersEnabledAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Testeventtriggersenabled attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -514,6 +1105,65 @@ class GeneralDiagnosticsCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -552,6 +1202,65 @@ class GeneralDiagnosticsCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -590,6 +1299,63 @@ class GeneralDiagnosticsCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -628,6 +1394,63 @@ class GeneralDiagnosticsCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -659,6 +1482,56 @@ class GeneralDiagnosticsCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -690,6 +1563,58 @@ class GeneralDiagnosticsCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(GeneralDiagnosticsCluster::class.java.name) const val CLUSTER_ID: UInt = 51u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/GroupKeyManagementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/GroupKeyManagementCluster.kt index cc3475b002cc88..7d6a660be3afb0 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/GroupKeyManagementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/GroupKeyManagementCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -46,16 +52,66 @@ class GroupKeyManagementCluster( class GroupKeyMapAttribute(val value: List) + sealed class GroupKeyMapAttributeSubscriptionState { + data class Success(val value: List) : + GroupKeyMapAttributeSubscriptionState() + + data class Error(val exception: Exception) : GroupKeyMapAttributeSubscriptionState() + + object SubscriptionEstablished : GroupKeyMapAttributeSubscriptionState() + } + class GroupTableAttribute(val value: List) + sealed class GroupTableAttributeSubscriptionState { + data class Success(val value: List) : + GroupTableAttributeSubscriptionState() + + data class Error(val exception: Exception) : GroupTableAttributeSubscriptionState() + + object SubscriptionEstablished : GroupTableAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun keySetWrite( groupKeySet: GroupKeyManagementClusterGroupKeySetStruct, timedInvokeTimeout: Duration? = null @@ -283,6 +339,63 @@ class GroupKeyManagementCluster( } } + suspend fun subscribeGroupKeyMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GroupKeyMapAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Groupkeymap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(GroupKeyManagementClusterGroupKeyMapStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(GroupKeyMapAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GroupKeyMapAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGroupTableAttribute(): GroupTableAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -321,6 +434,63 @@ class GroupKeyManagementCluster( return GroupTableAttribute(decodedValue) } + suspend fun subscribeGroupTableAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GroupTableAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Grouptable attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(GroupKeyManagementClusterGroupInfoMapStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(GroupTableAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GroupTableAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxGroupsPerFabricAttribute(): UShort { val ATTRIBUTE_ID: UInt = 2u @@ -352,6 +522,58 @@ class GroupKeyManagementCluster( return decodedValue } + suspend fun subscribeMaxGroupsPerFabricAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxgroupsperfabric attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxGroupKeysPerFabricAttribute(): UShort { val ATTRIBUTE_ID: UInt = 3u @@ -383,6 +605,58 @@ class GroupKeyManagementCluster( return decodedValue } + suspend fun subscribeMaxGroupKeysPerFabricAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxgroupkeysperfabric attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -421,6 +695,65 @@ class GroupKeyManagementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -459,6 +792,65 @@ class GroupKeyManagementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -497,6 +889,63 @@ class GroupKeyManagementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -535,6 +984,63 @@ class GroupKeyManagementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -566,6 +1072,56 @@ class GroupKeyManagementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -597,6 +1153,58 @@ class GroupKeyManagementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(GroupKeyManagementCluster::class.java.name) const val CLUSTER_ID: UInt = 63u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/GroupsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/GroupsCluster.kt index d79567217cc8ba..ca466afbdd0f61 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/GroupsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/GroupsCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -44,12 +51,44 @@ class GroupsCluster(private val controller: MatterController, private val endpoi class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun addGroup( groupID: UShort, groupName: String, @@ -389,6 +428,56 @@ class GroupsCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeNameSupportAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Namesupport attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -427,6 +516,65 @@ class GroupsCluster(private val controller: MatterController, private val endpoi return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -465,6 +613,65 @@ class GroupsCluster(private val controller: MatterController, private val endpoi return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -503,6 +710,63 @@ class GroupsCluster(private val controller: MatterController, private val endpoi return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -541,6 +805,63 @@ class GroupsCluster(private val controller: MatterController, private val endpoi return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -572,6 +893,56 @@ class GroupsCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -603,6 +974,58 @@ class GroupsCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(GroupsCluster::class.java.name) const val CLUSTER_ID: UInt = 4u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/HepaFilterMonitoringCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/HepaFilterMonitoringCluster.kt index a4ba1749b006f4..4d7d42bebb7c47 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/HepaFilterMonitoringCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/HepaFilterMonitoringCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -41,18 +49,67 @@ class HepaFilterMonitoringCluster( ) { class LastChangedTimeAttribute(val value: UInt?) + sealed class LastChangedTimeAttributeSubscriptionState { + data class Success(val value: UInt?) : LastChangedTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : LastChangedTimeAttributeSubscriptionState() + + object SubscriptionEstablished : LastChangedTimeAttributeSubscriptionState() + } + class ReplacementProductListAttribute( val value: List? ) + sealed class ReplacementProductListAttributeSubscriptionState { + data class Success(val value: List?) : + ReplacementProductListAttributeSubscriptionState() + + data class Error(val exception: Exception) : ReplacementProductListAttributeSubscriptionState() + + object SubscriptionEstablished : ReplacementProductListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun resetCondition(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -107,6 +164,61 @@ class HepaFilterMonitoringCluster( return decodedValue } + suspend fun subscribeConditionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Condition attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDegradationDirectionAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 1u @@ -143,6 +255,63 @@ class HepaFilterMonitoringCluster( return decodedValue } + suspend fun subscribeDegradationDirectionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Degradationdirection attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readChangeIndicationAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -174,6 +343,58 @@ class HepaFilterMonitoringCluster( return decodedValue } + suspend fun subscribeChangeIndicationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Changeindication attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInPlaceIndicatorAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 3u @@ -210,6 +431,63 @@ class HepaFilterMonitoringCluster( return decodedValue } + suspend fun subscribeInPlaceIndicatorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Inplaceindicator attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLastChangedTimeAttribute(): LastChangedTimeAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -291,6 +569,68 @@ class HepaFilterMonitoringCluster( } } + suspend fun subscribeLastChangedTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LastChangedTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lastchangedtime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LastChangedTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LastChangedTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readReplacementProductListAttribute(): ReplacementProductListAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -335,6 +675,74 @@ class HepaFilterMonitoringCluster( return ReplacementProductListAttribute(decodedValue) } + suspend fun subscribeReplacementProductListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ReplacementProductListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Replacementproductlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + HepaFilterMonitoringClusterReplacementProductStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ReplacementProductListAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ReplacementProductListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -373,6 +781,65 @@ class HepaFilterMonitoringCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -411,6 +878,65 @@ class HepaFilterMonitoringCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -449,6 +975,63 @@ class HepaFilterMonitoringCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -487,6 +1070,63 @@ class HepaFilterMonitoringCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -518,6 +1158,56 @@ class HepaFilterMonitoringCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -549,6 +1239,58 @@ class HepaFilterMonitoringCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(HepaFilterMonitoringCluster::class.java.name) const val CLUSTER_ID: UInt = 113u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt index 4490879d7fe247..ae6a817badc134 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/IcdManagementCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -45,14 +52,55 @@ class IcdManagementCluster( val value: List? ) + sealed class RegisteredClientsAttributeSubscriptionState { + data class Success(val value: List?) : + RegisteredClientsAttributeSubscriptionState() + + data class Error(val exception: Exception) : RegisteredClientsAttributeSubscriptionState() + + object SubscriptionEstablished : RegisteredClientsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun registerClient( checkInNodeID: ULong, monitoredSubject: ULong, @@ -216,6 +264,58 @@ class IcdManagementCluster( return decodedValue } + suspend fun subscribeIdleModeDurationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Idlemodeduration attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveModeDurationAttribute(): UInt { val ATTRIBUTE_ID: UInt = 1u @@ -247,6 +347,58 @@ class IcdManagementCluster( return decodedValue } + suspend fun subscribeActiveModeDurationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activemodeduration attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveModeThresholdAttribute(): UShort { val ATTRIBUTE_ID: UInt = 2u @@ -278,6 +430,58 @@ class IcdManagementCluster( return decodedValue } + suspend fun subscribeActiveModeThresholdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activemodethreshold attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRegisteredClientsAttribute(): RegisteredClientsAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -320,6 +524,74 @@ class IcdManagementCluster( return RegisteredClientsAttribute(decodedValue) } + suspend fun subscribeRegisteredClientsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + RegisteredClientsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Registeredclients attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + IcdManagementClusterMonitoringRegistrationStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(RegisteredClientsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(RegisteredClientsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readICDCounterAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -356,6 +628,61 @@ class IcdManagementCluster( return decodedValue } + suspend fun subscribeICDCounterAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Icdcounter attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClientsSupportedPerFabricAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 5u @@ -392,6 +719,63 @@ class IcdManagementCluster( return decodedValue } + suspend fun subscribeClientsSupportedPerFabricAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clientssupportedperfabric attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUserActiveModeTriggerHintAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -428,6 +812,63 @@ class IcdManagementCluster( return decodedValue } + suspend fun subscribeUserActiveModeTriggerHintAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Useractivemodetriggerhint attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUserActiveModeTriggerInstructionAttribute(): String? { val ATTRIBUTE_ID: UInt = 7u @@ -466,6 +907,63 @@ class IcdManagementCluster( return decodedValue } + suspend fun subscribeUserActiveModeTriggerInstructionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Useractivemodetriggerinstruction attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -504,6 +1002,65 @@ class IcdManagementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -542,6 +1099,65 @@ class IcdManagementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -580,6 +1196,63 @@ class IcdManagementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -618,6 +1291,63 @@ class IcdManagementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -649,6 +1379,56 @@ class IcdManagementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -680,6 +1460,58 @@ class IcdManagementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(IcdManagementCluster::class.java.name) const val CLUSTER_ID: UInt = 70u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/IdentifyCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/IdentifyCluster.kt index 2221b5362e2620..f7ed262f1a73ba 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/IdentifyCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/IdentifyCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -39,12 +46,44 @@ import matter.tlv.TlvWriter class IdentifyCluster(private val controller: MatterController, private val endpointId: UShort) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun identify(identifyTime: UShort, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -165,6 +204,56 @@ class IdentifyCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeIdentifyTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Identifytime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readIdentifyTypeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -196,6 +285,56 @@ class IdentifyCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeIdentifyTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Identifytype attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -234,6 +373,65 @@ class IdentifyCluster(private val controller: MatterController, private val endp return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -272,6 +470,65 @@ class IdentifyCluster(private val controller: MatterController, private val endp return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -310,6 +567,63 @@ class IdentifyCluster(private val controller: MatterController, private val endp return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -348,6 +662,63 @@ class IdentifyCluster(private val controller: MatterController, private val endp return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -379,6 +750,56 @@ class IdentifyCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -410,6 +831,58 @@ class IdentifyCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(IdentifyCluster::class.java.name) const val CLUSTER_ID: UInt = 3u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/IlluminanceMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/IlluminanceMeasurementCluster.kt index df1c954e98f276..3fbcfa85674aff 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/IlluminanceMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/IlluminanceMeasurementCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,20 +40,84 @@ class IlluminanceMeasurementCluster( ) { class MeasuredValueAttribute(val value: UShort?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: UShort?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: UShort?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: UShort?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: UShort?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: UShort?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class LightSensorTypeAttribute(val value: UByte?) + sealed class LightSensorTypeAttributeSubscriptionState { + data class Success(val value: UByte?) : LightSensorTypeAttributeSubscriptionState() + + data class Error(val exception: Exception) : LightSensorTypeAttributeSubscriptionState() + + object SubscriptionEstablished : LightSensorTypeAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -84,6 +155,62 @@ class IlluminanceMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -121,6 +248,64 @@ class IlluminanceMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -158,6 +343,64 @@ class IlluminanceMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readToleranceAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 3u @@ -194,6 +437,61 @@ class IlluminanceMeasurementCluster( return decodedValue } + suspend fun subscribeToleranceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Tolerance attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLightSensorTypeAttribute(): LightSensorTypeAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -235,6 +533,68 @@ class IlluminanceMeasurementCluster( return LightSensorTypeAttribute(decodedValue) } + suspend fun subscribeLightSensorTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LightSensorTypeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lightsensortype attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LightSensorTypeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LightSensorTypeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -273,6 +633,65 @@ class IlluminanceMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -311,6 +730,65 @@ class IlluminanceMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -349,6 +827,63 @@ class IlluminanceMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -387,6 +922,63 @@ class IlluminanceMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -418,6 +1010,56 @@ class IlluminanceMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -449,6 +1091,58 @@ class IlluminanceMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(IlluminanceMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1024u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/KeypadInputCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/KeypadInputCluster.kt index edd6d8df5dc73a..8e65a58bb20e56 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/KeypadInputCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/KeypadInputCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -38,12 +44,44 @@ class KeypadInputCluster(private val controller: MatterController, private val e class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun sendKey(keyCode: UByte, timedInvokeTimeout: Duration? = null): SendKeyResponse { val commandId: UInt = 0u @@ -126,6 +164,65 @@ class KeypadInputCluster(private val controller: MatterController, private val e return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -164,6 +261,65 @@ class KeypadInputCluster(private val controller: MatterController, private val e return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -202,6 +358,63 @@ class KeypadInputCluster(private val controller: MatterController, private val e return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -240,6 +453,63 @@ class KeypadInputCluster(private val controller: MatterController, private val e return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -271,6 +541,56 @@ class KeypadInputCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -302,6 +622,58 @@ class KeypadInputCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(KeypadInputCluster::class.java.name) const val CLUSTER_ID: UInt = 1289u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryDryerControlsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryDryerControlsCluster.kt index af35edb3cfc343..f782f3ec082767 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryDryerControlsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryDryerControlsCluster.kt @@ -20,9 +20,15 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,16 +44,64 @@ class LaundryDryerControlsCluster( ) { class SupportedDrynessLevelsAttribute(val value: List) + sealed class SupportedDrynessLevelsAttributeSubscriptionState { + data class Success(val value: List) : SupportedDrynessLevelsAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedDrynessLevelsAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedDrynessLevelsAttributeSubscriptionState() + } + class SelectedDrynessLevelAttribute(val value: UByte?) + sealed class SelectedDrynessLevelAttributeSubscriptionState { + data class Success(val value: UByte?) : SelectedDrynessLevelAttributeSubscriptionState() + + data class Error(val exception: Exception) : SelectedDrynessLevelAttributeSubscriptionState() + + object SubscriptionEstablished : SelectedDrynessLevelAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readSupportedDrynessLevelsAttribute(): SupportedDrynessLevelsAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -86,6 +140,65 @@ class LaundryDryerControlsCluster( return SupportedDrynessLevelsAttribute(decodedValue) } + suspend fun subscribeSupportedDrynessLevelsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedDrynessLevelsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supporteddrynesslevels attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(SupportedDrynessLevelsAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedDrynessLevelsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSelectedDrynessLevelAttribute(): SelectedDrynessLevelAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -166,6 +279,64 @@ class LaundryDryerControlsCluster( } } + suspend fun subscribeSelectedDrynessLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SelectedDrynessLevelAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Selecteddrynesslevel attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SelectedDrynessLevelAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SelectedDrynessLevelAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -204,6 +375,65 @@ class LaundryDryerControlsCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -242,6 +472,65 @@ class LaundryDryerControlsCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -280,6 +569,63 @@ class LaundryDryerControlsCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -318,6 +664,63 @@ class LaundryDryerControlsCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -349,6 +752,56 @@ class LaundryDryerControlsCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -380,6 +833,58 @@ class LaundryDryerControlsCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(LaundryDryerControlsCluster::class.java.name) const val CLUSTER_ID: UInt = 74u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryWasherControlsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryWasherControlsCluster.kt index 95eefba0038d85..42b5ed96fc640a 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryWasherControlsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryWasherControlsCluster.kt @@ -20,9 +20,16 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,18 +45,74 @@ class LaundryWasherControlsCluster( ) { class SpinSpeedsAttribute(val value: List?) + sealed class SpinSpeedsAttributeSubscriptionState { + data class Success(val value: List?) : SpinSpeedsAttributeSubscriptionState() + + data class Error(val exception: Exception) : SpinSpeedsAttributeSubscriptionState() + + object SubscriptionEstablished : SpinSpeedsAttributeSubscriptionState() + } + class SpinSpeedCurrentAttribute(val value: UByte?) + sealed class SpinSpeedCurrentAttributeSubscriptionState { + data class Success(val value: UByte?) : SpinSpeedCurrentAttributeSubscriptionState() + + data class Error(val exception: Exception) : SpinSpeedCurrentAttributeSubscriptionState() + + object SubscriptionEstablished : SpinSpeedCurrentAttributeSubscriptionState() + } + class SupportedRinsesAttribute(val value: List?) + sealed class SupportedRinsesAttributeSubscriptionState { + data class Success(val value: List?) : SupportedRinsesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedRinsesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedRinsesAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readSpinSpeedsAttribute(): SpinSpeedsAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -92,6 +155,67 @@ class LaundryWasherControlsCluster( return SpinSpeedsAttribute(decodedValue) } + suspend fun subscribeSpinSpeedsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SpinSpeedsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Spinspeeds attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getString(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(SpinSpeedsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SpinSpeedsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSpinSpeedCurrentAttribute(): SpinSpeedCurrentAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -173,6 +297,68 @@ class LaundryWasherControlsCluster( } } + suspend fun subscribeSpinSpeedCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SpinSpeedCurrentAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Spinspeedcurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SpinSpeedCurrentAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SpinSpeedCurrentAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfRinsesAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -249,6 +435,63 @@ class LaundryWasherControlsCluster( } } + suspend fun subscribeNumberOfRinsesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofrinses attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedRinsesAttribute(): SupportedRinsesAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -291,6 +534,69 @@ class LaundryWasherControlsCluster( return SupportedRinsesAttribute(decodedValue) } + suspend fun subscribeSupportedRinsesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedRinsesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedrinses attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(SupportedRinsesAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedRinsesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -329,6 +635,65 @@ class LaundryWasherControlsCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -367,6 +732,65 @@ class LaundryWasherControlsCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -405,6 +829,63 @@ class LaundryWasherControlsCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -443,6 +924,63 @@ class LaundryWasherControlsCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -474,6 +1012,56 @@ class LaundryWasherControlsCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -505,6 +1093,58 @@ class LaundryWasherControlsCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(LaundryWasherControlsCluster::class.java.name) const val CLUSTER_ID: UInt = 83u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryWasherModeCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryWasherModeCluster.kt index 35b8147a67cbcf..39984ca8d45b8c 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryWasherModeCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/LaundryWasherModeCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -44,18 +51,75 @@ class LaundryWasherModeCluster( class SupportedModesAttribute(val value: List) + sealed class SupportedModesAttributeSubscriptionState { + data class Success(val value: List) : + SupportedModesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedModesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedModesAttributeSubscriptionState() + } + class StartUpModeAttribute(val value: UByte?) + sealed class StartUpModeAttributeSubscriptionState { + data class Success(val value: UByte?) : StartUpModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : StartUpModeAttributeSubscriptionState() + + object SubscriptionEstablished : StartUpModeAttributeSubscriptionState() + } + class OnModeAttribute(val value: UByte?) + sealed class OnModeAttributeSubscriptionState { + data class Success(val value: UByte?) : OnModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnModeAttributeSubscriptionState() + + object SubscriptionEstablished : OnModeAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun changeToMode( newMode: UByte, timedInvokeTimeout: Duration? = null @@ -158,6 +222,65 @@ class LaundryWasherModeCluster( return SupportedModesAttribute(decodedValue) } + suspend fun subscribeSupportedModesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedModesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedmodes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(LaundryWasherModeClusterModeOptionStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(SupportedModesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedModesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -189,6 +312,56 @@ class LaundryWasherModeCluster( return decodedValue } + suspend fun subscribeCurrentModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartUpModeAttribute(): StartUpModeAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -270,6 +443,66 @@ class LaundryWasherModeCluster( } } + suspend fun subscribeStartUpModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StartUpModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Startupmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StartUpModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StartUpModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnModeAttribute(): OnModeAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -351,6 +584,66 @@ class LaundryWasherModeCluster( } } + suspend fun subscribeOnModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Onmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OnModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -389,6 +682,65 @@ class LaundryWasherModeCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -427,6 +779,65 @@ class LaundryWasherModeCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -465,6 +876,63 @@ class LaundryWasherModeCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -503,6 +971,63 @@ class LaundryWasherModeCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -534,6 +1059,56 @@ class LaundryWasherModeCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -565,6 +1140,58 @@ class LaundryWasherModeCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(LaundryWasherModeCluster::class.java.name) const val CLUSTER_ID: UInt = 81u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/LevelControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/LevelControlCluster.kt index df407d6f1fe71e..aa67210f9b5551 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/LevelControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/LevelControlCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -42,24 +49,104 @@ class LevelControlCluster( ) { class CurrentLevelAttribute(val value: UByte?) + sealed class CurrentLevelAttributeSubscriptionState { + data class Success(val value: UByte?) : CurrentLevelAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentLevelAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentLevelAttributeSubscriptionState() + } + class OnLevelAttribute(val value: UByte?) + sealed class OnLevelAttributeSubscriptionState { + data class Success(val value: UByte?) : OnLevelAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnLevelAttributeSubscriptionState() + + object SubscriptionEstablished : OnLevelAttributeSubscriptionState() + } + class OnTransitionTimeAttribute(val value: UShort?) + sealed class OnTransitionTimeAttributeSubscriptionState { + data class Success(val value: UShort?) : OnTransitionTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnTransitionTimeAttributeSubscriptionState() + + object SubscriptionEstablished : OnTransitionTimeAttributeSubscriptionState() + } + class OffTransitionTimeAttribute(val value: UShort?) + sealed class OffTransitionTimeAttributeSubscriptionState { + data class Success(val value: UShort?) : OffTransitionTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : OffTransitionTimeAttributeSubscriptionState() + + object SubscriptionEstablished : OffTransitionTimeAttributeSubscriptionState() + } + class DefaultMoveRateAttribute(val value: UByte?) + sealed class DefaultMoveRateAttributeSubscriptionState { + data class Success(val value: UByte?) : DefaultMoveRateAttributeSubscriptionState() + + data class Error(val exception: Exception) : DefaultMoveRateAttributeSubscriptionState() + + object SubscriptionEstablished : DefaultMoveRateAttributeSubscriptionState() + } + class StartUpCurrentLevelAttribute(val value: UByte?) + sealed class StartUpCurrentLevelAttributeSubscriptionState { + data class Success(val value: UByte?) : StartUpCurrentLevelAttributeSubscriptionState() + + data class Error(val exception: Exception) : StartUpCurrentLevelAttributeSubscriptionState() + + object SubscriptionEstablished : StartUpCurrentLevelAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun moveToLevel( level: UByte, transitionTime: UShort?, @@ -406,6 +493,62 @@ class LevelControlCluster( return CurrentLevelAttribute(decodedValue) } + suspend fun subscribeCurrentLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentLevelAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentlevel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentLevelAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentLevelAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRemainingTimeAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1u @@ -442,6 +585,61 @@ class LevelControlCluster( return decodedValue } + suspend fun subscribeRemainingTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Remainingtime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinLevelAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -478,6 +676,61 @@ class LevelControlCluster( return decodedValue } + suspend fun subscribeMinLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Minlevel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxLevelAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 3u @@ -514,6 +767,61 @@ class LevelControlCluster( return decodedValue } + suspend fun subscribeMaxLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxlevel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentFrequencyAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 4u @@ -550,6 +858,63 @@ class LevelControlCluster( return decodedValue } + suspend fun subscribeCurrentFrequencyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentfrequency attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinFrequencyAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 5u @@ -586,6 +951,61 @@ class LevelControlCluster( return decodedValue } + suspend fun subscribeMinFrequencyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Minfrequency attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxFrequencyAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 6u @@ -622,6 +1042,61 @@ class LevelControlCluster( return decodedValue } + suspend fun subscribeMaxFrequencyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxfrequency attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOptionsAttribute(): UByte { val ATTRIBUTE_ID: UInt = 15u @@ -693,6 +1168,56 @@ class LevelControlCluster( } } + suspend fun subscribeOptionsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 15u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Options attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnOffTransitionTimeAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16u @@ -772,6 +1297,63 @@ class LevelControlCluster( } } + suspend fun subscribeOnOffTransitionTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Onofftransitiontime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnLevelAttribute(): OnLevelAttribute { val ATTRIBUTE_ID: UInt = 17u @@ -849,6 +1431,62 @@ class LevelControlCluster( } } + suspend fun subscribeOnLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnLevelAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Onlevel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OnLevelAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnLevelAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnTransitionTimeAttribute(): OnTransitionTimeAttribute { val ATTRIBUTE_ID: UInt = 18u @@ -930,6 +1568,68 @@ class LevelControlCluster( } } + suspend fun subscribeOnTransitionTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnTransitionTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Ontransitiontime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OnTransitionTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnTransitionTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOffTransitionTimeAttribute(): OffTransitionTimeAttribute { val ATTRIBUTE_ID: UInt = 19u @@ -1011,6 +1711,68 @@ class LevelControlCluster( } } + suspend fun subscribeOffTransitionTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OffTransitionTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Offtransitiontime attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OffTransitionTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OffTransitionTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDefaultMoveRateAttribute(): DefaultMoveRateAttribute { val ATTRIBUTE_ID: UInt = 20u @@ -1092,6 +1854,68 @@ class LevelControlCluster( } } + suspend fun subscribeDefaultMoveRateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DefaultMoveRateAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Defaultmoverate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(DefaultMoveRateAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(DefaultMoveRateAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartUpCurrentLevelAttribute(): StartUpCurrentLevelAttribute { val ATTRIBUTE_ID: UInt = 16384u @@ -1173,6 +1997,68 @@ class LevelControlCluster( } } + suspend fun subscribeStartUpCurrentLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16384u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StartUpCurrentLevelAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Startupcurrentlevel attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StartUpCurrentLevelAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StartUpCurrentLevelAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1211,6 +2097,65 @@ class LevelControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1249,6 +2194,65 @@ class LevelControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1287,6 +2291,63 @@ class LevelControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1325,6 +2386,63 @@ class LevelControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1356,6 +2474,56 @@ class LevelControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1387,6 +2555,58 @@ class LevelControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(LevelControlCluster::class.java.name) const val CLUSTER_ID: UInt = 8u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/LocalizationConfigurationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/LocalizationConfigurationCluster.kt index e5f61296f676f2..3eb0f7f602ddea 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/LocalizationConfigurationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/LocalizationConfigurationCluster.kt @@ -20,9 +20,16 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,14 +45,54 @@ class LocalizationConfigurationCluster( ) { class SupportedLocalesAttribute(val value: List) + sealed class SupportedLocalesAttributeSubscriptionState { + data class Success(val value: List) : SupportedLocalesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedLocalesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedLocalesAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readActiveLocaleAttribute(): String { val ATTRIBUTE_ID: UInt = 0u @@ -117,6 +164,56 @@ class LocalizationConfigurationCluster( } } + suspend fun subscribeActiveLocaleAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Activelocale attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedLocalesAttribute(): SupportedLocalesAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -155,6 +252,65 @@ class LocalizationConfigurationCluster( return SupportedLocalesAttribute(decodedValue) } + suspend fun subscribeSupportedLocalesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedLocalesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedlocales attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getString(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(SupportedLocalesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedLocalesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -193,6 +349,65 @@ class LocalizationConfigurationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -231,6 +446,65 @@ class LocalizationConfigurationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -269,6 +543,63 @@ class LocalizationConfigurationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -307,6 +638,63 @@ class LocalizationConfigurationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -338,6 +726,56 @@ class LocalizationConfigurationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -369,6 +807,58 @@ class LocalizationConfigurationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(LocalizationConfigurationCluster::class.java.name) const val CLUSTER_ID: UInt = 43u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/LowPowerCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/LowPowerCluster.kt index b0ed37c7aaa582..b0ca32ffc850b8 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/LowPowerCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/LowPowerCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -35,12 +41,44 @@ import matter.tlv.TlvWriter class LowPowerCluster(private val controller: MatterController, private val endpointId: UShort) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun sleep(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -97,6 +135,65 @@ class LowPowerCluster(private val controller: MatterController, private val endp return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -135,6 +232,65 @@ class LowPowerCluster(private val controller: MatterController, private val endp return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -173,6 +329,63 @@ class LowPowerCluster(private val controller: MatterController, private val endp return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -211,6 +424,63 @@ class LowPowerCluster(private val controller: MatterController, private val endp return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -242,6 +512,56 @@ class LowPowerCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -273,6 +593,58 @@ class LowPowerCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(LowPowerCluster::class.java.name) const val CLUSTER_ID: UInt = 1288u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/MediaInputCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/MediaInputCluster.kt index 1dc12b37ae620b..96e656cd0a7bc9 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/MediaInputCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/MediaInputCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -36,14 +43,55 @@ import matter.tlv.TlvWriter class MediaInputCluster(private val controller: MatterController, private val endpointId: UShort) { class InputListAttribute(val value: List) + sealed class InputListAttributeSubscriptionState { + data class Success(val value: List) : + InputListAttributeSubscriptionState() + + data class Error(val exception: Exception) : InputListAttributeSubscriptionState() + + object SubscriptionEstablished : InputListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun selectInput(index: UByte, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -163,6 +211,63 @@ class MediaInputCluster(private val controller: MatterController, private val en return InputListAttribute(decodedValue) } + suspend fun subscribeInputListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + InputListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Inputlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(MediaInputClusterInputInfoStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(InputListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(InputListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentInputAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -194,6 +299,56 @@ class MediaInputCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeCurrentInputAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentinput attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -232,6 +387,65 @@ class MediaInputCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -270,6 +484,65 @@ class MediaInputCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -308,6 +581,63 @@ class MediaInputCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -346,6 +676,63 @@ class MediaInputCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -377,6 +764,56 @@ class MediaInputCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -408,6 +845,58 @@ class MediaInputCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(MediaInputCluster::class.java.name) const val CLUSTER_ID: UInt = 1287u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/MediaPlaybackCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/MediaPlaybackCluster.kt index ffe9e82a9c616a..12b2afd339765b 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/MediaPlaybackCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/MediaPlaybackCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,30 +49,139 @@ class MediaPlaybackCluster( class StartTimeAttribute(val value: ULong?) + sealed class StartTimeAttributeSubscriptionState { + data class Success(val value: ULong?) : StartTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : StartTimeAttributeSubscriptionState() + + object SubscriptionEstablished : StartTimeAttributeSubscriptionState() + } + class DurationAttribute(val value: ULong?) + sealed class DurationAttributeSubscriptionState { + data class Success(val value: ULong?) : DurationAttributeSubscriptionState() + + data class Error(val exception: Exception) : DurationAttributeSubscriptionState() + + object SubscriptionEstablished : DurationAttributeSubscriptionState() + } + class SampledPositionAttribute(val value: MediaPlaybackClusterPlaybackPositionStruct?) + sealed class SampledPositionAttributeSubscriptionState { + data class Success(val value: MediaPlaybackClusterPlaybackPositionStruct?) : + SampledPositionAttributeSubscriptionState() + + data class Error(val exception: Exception) : SampledPositionAttributeSubscriptionState() + + object SubscriptionEstablished : SampledPositionAttributeSubscriptionState() + } + class SeekRangeEndAttribute(val value: ULong?) + sealed class SeekRangeEndAttributeSubscriptionState { + data class Success(val value: ULong?) : SeekRangeEndAttributeSubscriptionState() + + data class Error(val exception: Exception) : SeekRangeEndAttributeSubscriptionState() + + object SubscriptionEstablished : SeekRangeEndAttributeSubscriptionState() + } + class SeekRangeStartAttribute(val value: ULong?) + sealed class SeekRangeStartAttributeSubscriptionState { + data class Success(val value: ULong?) : SeekRangeStartAttributeSubscriptionState() + + data class Error(val exception: Exception) : SeekRangeStartAttributeSubscriptionState() + + object SubscriptionEstablished : SeekRangeStartAttributeSubscriptionState() + } + class ActiveAudioTrackAttribute(val value: MediaPlaybackClusterTrackStruct?) + sealed class ActiveAudioTrackAttributeSubscriptionState { + data class Success(val value: MediaPlaybackClusterTrackStruct?) : + ActiveAudioTrackAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveAudioTrackAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveAudioTrackAttributeSubscriptionState() + } + class AvailableAudioTracksAttribute(val value: List?) + sealed class AvailableAudioTracksAttributeSubscriptionState { + data class Success(val value: List?) : + AvailableAudioTracksAttributeSubscriptionState() + + data class Error(val exception: Exception) : AvailableAudioTracksAttributeSubscriptionState() + + object SubscriptionEstablished : AvailableAudioTracksAttributeSubscriptionState() + } + class ActiveTextTrackAttribute(val value: MediaPlaybackClusterTrackStruct?) + sealed class ActiveTextTrackAttributeSubscriptionState { + data class Success(val value: MediaPlaybackClusterTrackStruct?) : + ActiveTextTrackAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveTextTrackAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveTextTrackAttributeSubscriptionState() + } + class AvailableTextTracksAttribute(val value: List?) + sealed class AvailableTextTracksAttributeSubscriptionState { + data class Success(val value: List?) : + AvailableTextTracksAttributeSubscriptionState() + + data class Error(val exception: Exception) : AvailableTextTracksAttributeSubscriptionState() + + object SubscriptionEstablished : AvailableTextTracksAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun play(timedInvokeTimeout: Duration? = null): PlaybackResponse { val commandId: UInt = 0u @@ -838,6 +955,56 @@ class MediaPlaybackCluster( return decodedValue } + suspend fun subscribeCurrentStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentstate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartTimeAttribute(): StartTimeAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -879,6 +1046,66 @@ class MediaPlaybackCluster( return StartTimeAttribute(decodedValue) } + suspend fun subscribeStartTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StartTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Starttime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StartTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StartTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDurationAttribute(): DurationAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -920,6 +1147,66 @@ class MediaPlaybackCluster( return DurationAttribute(decodedValue) } + suspend fun subscribeDurationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DurationAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Duration attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(DurationAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(DurationAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSampledPositionAttribute(): SampledPositionAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -961,6 +1248,68 @@ class MediaPlaybackCluster( return SampledPositionAttribute(decodedValue) } + suspend fun subscribeSampledPositionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SampledPositionAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Sampledposition attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: MediaPlaybackClusterPlaybackPositionStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + MediaPlaybackClusterPlaybackPositionStruct.fromTlv(AnonymousTag, tlvReader) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SampledPositionAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SampledPositionAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPlaybackSpeedAttribute(): Float? { val ATTRIBUTE_ID: UInt = 4u @@ -997,6 +1346,61 @@ class MediaPlaybackCluster( return decodedValue } + suspend fun subscribePlaybackSpeedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Playbackspeed attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSeekRangeEndAttribute(): SeekRangeEndAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -1038,6 +1442,66 @@ class MediaPlaybackCluster( return SeekRangeEndAttribute(decodedValue) } + suspend fun subscribeSeekRangeEndAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SeekRangeEndAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Seekrangeend attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SeekRangeEndAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SeekRangeEndAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSeekRangeStartAttribute(): SeekRangeStartAttribute { val ATTRIBUTE_ID: UInt = 6u @@ -1079,6 +1543,68 @@ class MediaPlaybackCluster( return SeekRangeStartAttribute(decodedValue) } + suspend fun subscribeSeekRangeStartAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SeekRangeStartAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Seekrangestart attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SeekRangeStartAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SeekRangeStartAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveAudioTrackAttribute(): ActiveAudioTrackAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -1120,6 +1646,68 @@ class MediaPlaybackCluster( return ActiveAudioTrackAttribute(decodedValue) } + suspend fun subscribeActiveAudioTrackAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveAudioTrackAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activeaudiotrack attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: MediaPlaybackClusterTrackStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + MediaPlaybackClusterTrackStruct.fromTlv(AnonymousTag, tlvReader) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ActiveAudioTrackAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveAudioTrackAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAvailableAudioTracksAttribute(): AvailableAudioTracksAttribute { val ATTRIBUTE_ID: UInt = 8u @@ -1167,6 +1755,74 @@ class MediaPlaybackCluster( return AvailableAudioTracksAttribute(decodedValue) } + suspend fun subscribeAvailableAudioTracksAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AvailableAudioTracksAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Availableaudiotracks attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(MediaPlaybackClusterTrackStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AvailableAudioTracksAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AvailableAudioTracksAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveTextTrackAttribute(): ActiveTextTrackAttribute { val ATTRIBUTE_ID: UInt = 9u @@ -1208,6 +1864,68 @@ class MediaPlaybackCluster( return ActiveTextTrackAttribute(decodedValue) } + suspend fun subscribeActiveTextTrackAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveTextTrackAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activetexttrack attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: MediaPlaybackClusterTrackStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + MediaPlaybackClusterTrackStruct.fromTlv(AnonymousTag, tlvReader) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ActiveTextTrackAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveTextTrackAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAvailableTextTracksAttribute(): AvailableTextTracksAttribute { val ATTRIBUTE_ID: UInt = 10u @@ -1255,6 +1973,74 @@ class MediaPlaybackCluster( return AvailableTextTracksAttribute(decodedValue) } + suspend fun subscribeAvailableTextTracksAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AvailableTextTracksAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Availabletexttracks attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(MediaPlaybackClusterTrackStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AvailableTextTracksAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AvailableTextTracksAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1293,6 +2079,65 @@ class MediaPlaybackCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1331,6 +2176,65 @@ class MediaPlaybackCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1369,6 +2273,63 @@ class MediaPlaybackCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1407,6 +2368,63 @@ class MediaPlaybackCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1438,6 +2456,56 @@ class MediaPlaybackCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1469,6 +2537,58 @@ class MediaPlaybackCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(MediaPlaybackCluster::class.java.name) const val CLUSTER_ID: UInt = 1286u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/MicrowaveOvenControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/MicrowaveOvenControlCluster.kt index cefaa3ed21eb54..fdb896c19ff9aa 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/MicrowaveOvenControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/MicrowaveOvenControlCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -39,12 +46,44 @@ class MicrowaveOvenControlCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun setCookingParameters( cookMode: UByte?, cookTime: UInt?, @@ -129,6 +168,56 @@ class MicrowaveOvenControlCluster( return decodedValue } + suspend fun subscribeCookTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Cooktime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPowerSettingAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -160,6 +249,56 @@ class MicrowaveOvenControlCluster( return decodedValue } + suspend fun subscribePowerSettingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Powersetting attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinPowerAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 3u @@ -196,6 +335,61 @@ class MicrowaveOvenControlCluster( return decodedValue } + suspend fun subscribeMinPowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Minpower attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxPowerAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 4u @@ -232,6 +426,61 @@ class MicrowaveOvenControlCluster( return decodedValue } + suspend fun subscribeMaxPowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxpower attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPowerStepAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 5u @@ -268,6 +517,61 @@ class MicrowaveOvenControlCluster( return decodedValue } + suspend fun subscribePowerStepAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Powerstep attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -306,6 +610,65 @@ class MicrowaveOvenControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -344,6 +707,65 @@ class MicrowaveOvenControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -382,6 +804,63 @@ class MicrowaveOvenControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -420,6 +899,63 @@ class MicrowaveOvenControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -451,6 +987,56 @@ class MicrowaveOvenControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -482,6 +1068,58 @@ class MicrowaveOvenControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(MicrowaveOvenControlCluster::class.java.name) const val CLUSTER_ID: UInt = 95u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/MicrowaveOvenModeCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/MicrowaveOvenModeCluster.kt index 77196e06d86eba..8362dcb4500717 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/MicrowaveOvenModeCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/MicrowaveOvenModeCluster.kt @@ -17,11 +17,19 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,14 +41,55 @@ class MicrowaveOvenModeCluster( ) { class SupportedModesAttribute(val value: List) + sealed class SupportedModesAttributeSubscriptionState { + data class Success(val value: List) : + SupportedModesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedModesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedModesAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readSupportedModesAttribute(): SupportedModesAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -79,6 +128,65 @@ class MicrowaveOvenModeCluster( return SupportedModesAttribute(decodedValue) } + suspend fun subscribeSupportedModesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedModesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedmodes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(MicrowaveOvenModeClusterModeOptionStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(SupportedModesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedModesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -110,6 +218,56 @@ class MicrowaveOvenModeCluster( return decodedValue } + suspend fun subscribeCurrentModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -148,6 +306,65 @@ class MicrowaveOvenModeCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -186,6 +403,65 @@ class MicrowaveOvenModeCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -224,6 +500,63 @@ class MicrowaveOvenModeCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -262,6 +595,63 @@ class MicrowaveOvenModeCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -293,6 +683,56 @@ class MicrowaveOvenModeCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -324,6 +764,58 @@ class MicrowaveOvenModeCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(MicrowaveOvenModeCluster::class.java.name) const val CLUSTER_ID: UInt = 94u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ModeSelectCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ModeSelectCluster.kt index 7c51d6eeb7a9f6..0119244a4e3865 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ModeSelectCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ModeSelectCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -39,20 +47,85 @@ import matter.tlv.TlvWriter class ModeSelectCluster(private val controller: MatterController, private val endpointId: UShort) { class StandardNamespaceAttribute(val value: UShort?) + sealed class StandardNamespaceAttributeSubscriptionState { + data class Success(val value: UShort?) : StandardNamespaceAttributeSubscriptionState() + + data class Error(val exception: Exception) : StandardNamespaceAttributeSubscriptionState() + + object SubscriptionEstablished : StandardNamespaceAttributeSubscriptionState() + } + class SupportedModesAttribute(val value: List) + sealed class SupportedModesAttributeSubscriptionState { + data class Success(val value: List) : + SupportedModesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedModesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedModesAttributeSubscriptionState() + } + class StartUpModeAttribute(val value: UByte?) + sealed class StartUpModeAttributeSubscriptionState { + data class Success(val value: UByte?) : StartUpModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : StartUpModeAttributeSubscriptionState() + + object SubscriptionEstablished : StartUpModeAttributeSubscriptionState() + } + class OnModeAttribute(val value: UByte?) + sealed class OnModeAttributeSubscriptionState { + data class Success(val value: UByte?) : OnModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnModeAttributeSubscriptionState() + + object SubscriptionEstablished : OnModeAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun changeToMode(newMode: UByte, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -105,6 +178,56 @@ class ModeSelectCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeDescriptionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Description attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStandardNamespaceAttribute(): StandardNamespaceAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -142,6 +265,64 @@ class ModeSelectCluster(private val controller: MatterController, private val en return StandardNamespaceAttribute(decodedValue) } + suspend fun subscribeStandardNamespaceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StandardNamespaceAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Standardnamespace attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StandardNamespaceAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StandardNamespaceAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedModesAttribute(): SupportedModesAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -180,6 +361,65 @@ class ModeSelectCluster(private val controller: MatterController, private val en return SupportedModesAttribute(decodedValue) } + suspend fun subscribeSupportedModesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedModesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedmodes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ModeSelectClusterModeOptionStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(SupportedModesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedModesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 3u @@ -211,6 +451,56 @@ class ModeSelectCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeCurrentModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartUpModeAttribute(): StartUpModeAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -292,6 +582,66 @@ class ModeSelectCluster(private val controller: MatterController, private val en } } + suspend fun subscribeStartUpModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StartUpModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Startupmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StartUpModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StartUpModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnModeAttribute(): OnModeAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -373,6 +723,66 @@ class ModeSelectCluster(private val controller: MatterController, private val en } } + suspend fun subscribeOnModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Onmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OnModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -411,6 +821,65 @@ class ModeSelectCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -449,6 +918,65 @@ class ModeSelectCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -487,6 +1015,63 @@ class ModeSelectCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -525,6 +1110,63 @@ class ModeSelectCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -556,6 +1198,56 @@ class ModeSelectCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -587,6 +1279,58 @@ class ModeSelectCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ModeSelectCluster::class.java.name) const val CLUSTER_ID: UInt = 80u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/NetworkCommissioningCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/NetworkCommissioningCluster.kt index c5e13a8eb0c0c4..c7568cff62a71f 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/NetworkCommissioningCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/NetworkCommissioningCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -65,22 +73,95 @@ class NetworkCommissioningCluster( class NetworksAttribute(val value: List) + sealed class NetworksAttributeSubscriptionState { + data class Success(val value: List) : + NetworksAttributeSubscriptionState() + + data class Error(val exception: Exception) : NetworksAttributeSubscriptionState() + + object SubscriptionEstablished : NetworksAttributeSubscriptionState() + } + class LastNetworkingStatusAttribute(val value: UByte?) + sealed class LastNetworkingStatusAttributeSubscriptionState { + data class Success(val value: UByte?) : LastNetworkingStatusAttributeSubscriptionState() + + data class Error(val exception: Exception) : LastNetworkingStatusAttributeSubscriptionState() + + object SubscriptionEstablished : LastNetworkingStatusAttributeSubscriptionState() + } + class LastNetworkIDAttribute(val value: ByteArray?) + sealed class LastNetworkIDAttributeSubscriptionState { + data class Success(val value: ByteArray?) : LastNetworkIDAttributeSubscriptionState() + + data class Error(val exception: Exception) : LastNetworkIDAttributeSubscriptionState() + + object SubscriptionEstablished : LastNetworkIDAttributeSubscriptionState() + } + class LastConnectErrorValueAttribute(val value: Int?) + sealed class LastConnectErrorValueAttributeSubscriptionState { + data class Success(val value: Int?) : LastConnectErrorValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : LastConnectErrorValueAttributeSubscriptionState() + + object SubscriptionEstablished : LastConnectErrorValueAttributeSubscriptionState() + } + class SupportedWiFiBandsAttribute(val value: List?) + sealed class SupportedWiFiBandsAttributeSubscriptionState { + data class Success(val value: List?) : SupportedWiFiBandsAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedWiFiBandsAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedWiFiBandsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun scanNetworks( ssid: ByteArray?, breadcrumb: ULong?, @@ -926,6 +1007,56 @@ class NetworkCommissioningCluster( return decodedValue } + suspend fun subscribeMaxNetworksAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxnetworks attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNetworksAttribute(): NetworksAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -964,6 +1095,63 @@ class NetworkCommissioningCluster( return NetworksAttribute(decodedValue) } + suspend fun subscribeNetworksAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NetworksAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Networks attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(NetworkCommissioningClusterNetworkInfoStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(NetworksAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(NetworksAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readScanMaxTimeSecondsAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -1000,6 +1188,63 @@ class NetworkCommissioningCluster( return decodedValue } + suspend fun subscribeScanMaxTimeSecondsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Scanmaxtimeseconds attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readConnectMaxTimeSecondsAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 3u @@ -1036,6 +1281,63 @@ class NetworkCommissioningCluster( return decodedValue } + suspend fun subscribeConnectMaxTimeSecondsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Connectmaxtimeseconds attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInterfaceEnabledAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 4u @@ -1107,6 +1409,58 @@ class NetworkCommissioningCluster( } } + suspend fun subscribeInterfaceEnabledAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Interfaceenabled attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLastNetworkingStatusAttribute(): LastNetworkingStatusAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -1144,6 +1498,64 @@ class NetworkCommissioningCluster( return LastNetworkingStatusAttribute(decodedValue) } + suspend fun subscribeLastNetworkingStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LastNetworkingStatusAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lastnetworkingstatus attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LastNetworkingStatusAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LastNetworkingStatusAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLastNetworkIDAttribute(): LastNetworkIDAttribute { val ATTRIBUTE_ID: UInt = 6u @@ -1181,6 +1593,62 @@ class NetworkCommissioningCluster( return LastNetworkIDAttribute(decodedValue) } + suspend fun subscribeLastNetworkIDAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LastNetworkIDAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Lastnetworkid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray? = + if (!tlvReader.isNull()) { + tlvReader.getByteArray(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LastNetworkIDAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LastNetworkIDAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLastConnectErrorValueAttribute(): LastConnectErrorValueAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -1218,6 +1686,64 @@ class NetworkCommissioningCluster( return LastConnectErrorValueAttribute(decodedValue) } + suspend fun subscribeLastConnectErrorValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LastConnectErrorValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lastconnecterrorvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Int? = + if (!tlvReader.isNull()) { + tlvReader.getInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LastConnectErrorValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LastConnectErrorValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedWiFiBandsAttribute(): SupportedWiFiBandsAttribute { val ATTRIBUTE_ID: UInt = 8u @@ -1260,6 +1786,69 @@ class NetworkCommissioningCluster( return SupportedWiFiBandsAttribute(decodedValue) } + suspend fun subscribeSupportedWiFiBandsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedWiFiBandsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedwifibands attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(SupportedWiFiBandsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedWiFiBandsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedThreadFeaturesAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 9u @@ -1296,6 +1885,63 @@ class NetworkCommissioningCluster( return decodedValue } + suspend fun subscribeSupportedThreadFeaturesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedthreadfeatures attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readThreadVersionAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 10u @@ -1332,6 +1978,61 @@ class NetworkCommissioningCluster( return decodedValue } + suspend fun subscribeThreadVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Threadversion attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1370,6 +2071,65 @@ class NetworkCommissioningCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1408,6 +2168,65 @@ class NetworkCommissioningCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1446,6 +2265,63 @@ class NetworkCommissioningCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1484,6 +2360,63 @@ class NetworkCommissioningCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1515,6 +2448,56 @@ class NetworkCommissioningCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1546,6 +2529,58 @@ class NetworkCommissioningCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(NetworkCommissioningCluster::class.java.name) const val CLUSTER_ID: UInt = 49u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/NitrogenDioxideConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/NitrogenDioxideConcentrationMeasurementCluster.kt index 715be5197a8d6f..d44ee68b808e62 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/NitrogenDioxideConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/NitrogenDioxideConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class NitrogenDioxideConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class NitrogenDioxideConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class NitrogenDioxideConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class NitrogenDioxideConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class NitrogenDioxideConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class NitrogenDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class NitrogenDioxideConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class NitrogenDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class NitrogenDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class NitrogenDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class NitrogenDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class NitrogenDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class NitrogenDioxideConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class NitrogenDioxideConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class NitrogenDioxideConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class NitrogenDioxideConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class NitrogenDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class NitrogenDioxideConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(NitrogenDioxideConcentrationMeasurementCluster::class.java.name) diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OccupancySensingCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OccupancySensingCluster.kt index 95b1f16986662b..8dd16f44cabe05 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OccupancySensingCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OccupancySensingCluster.kt @@ -20,9 +20,16 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,12 +45,44 @@ class OccupancySensingCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readOccupancyAttribute(): UByte { val ATTRIBUTE_ID: UInt = 0u @@ -75,6 +114,56 @@ class OccupancySensingCluster( return decodedValue } + suspend fun subscribeOccupancyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Occupancy attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOccupancySensorTypeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -106,6 +195,58 @@ class OccupancySensingCluster( return decodedValue } + suspend fun subscribeOccupancySensorTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Occupancysensortype attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOccupancySensorTypeBitmapAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -137,6 +278,58 @@ class OccupancySensingCluster( return decodedValue } + suspend fun subscribeOccupancySensorTypeBitmapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Occupancysensortypebitmap attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPIROccupiedToUnoccupiedDelayAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16u @@ -216,6 +409,63 @@ class OccupancySensingCluster( } } + suspend fun subscribePIROccupiedToUnoccupiedDelayAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Piroccupiedtounoccupieddelay attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPIRUnoccupiedToOccupiedDelayAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 17u @@ -295,6 +545,63 @@ class OccupancySensingCluster( } } + suspend fun subscribePIRUnoccupiedToOccupiedDelayAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Pirunoccupiedtooccupieddelay attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPIRUnoccupiedToOccupiedThresholdAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 18u @@ -376,6 +683,63 @@ class OccupancySensingCluster( } } + suspend fun subscribePIRUnoccupiedToOccupiedThresholdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Pirunoccupiedtooccupiedthreshold attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUltrasonicOccupiedToUnoccupiedDelayAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 32u @@ -457,6 +821,63 @@ class OccupancySensingCluster( } } + suspend fun subscribeUltrasonicOccupiedToUnoccupiedDelayAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 32u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Ultrasonicoccupiedtounoccupieddelay attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUltrasonicUnoccupiedToOccupiedDelayAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 33u @@ -538,6 +959,63 @@ class OccupancySensingCluster( } } + suspend fun subscribeUltrasonicUnoccupiedToOccupiedDelayAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 33u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Ultrasonicunoccupiedtooccupieddelay attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUltrasonicUnoccupiedToOccupiedThresholdAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 34u @@ -619,6 +1097,63 @@ class OccupancySensingCluster( } } + suspend fun subscribeUltrasonicUnoccupiedToOccupiedThresholdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 34u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Ultrasonicunoccupiedtooccupiedthreshold attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPhysicalContactOccupiedToUnoccupiedDelayAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 48u @@ -700,6 +1235,63 @@ class OccupancySensingCluster( } } + suspend fun subscribePhysicalContactOccupiedToUnoccupiedDelayAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 48u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Physicalcontactoccupiedtounoccupieddelay attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPhysicalContactUnoccupiedToOccupiedDelayAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 49u @@ -781,6 +1373,63 @@ class OccupancySensingCluster( } } + suspend fun subscribePhysicalContactUnoccupiedToOccupiedDelayAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 49u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Physicalcontactunoccupiedtooccupieddelay attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPhysicalContactUnoccupiedToOccupiedThresholdAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 50u @@ -862,6 +1511,63 @@ class OccupancySensingCluster( } } + suspend fun subscribePhysicalContactUnoccupiedToOccupiedThresholdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 50u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Physicalcontactunoccupiedtooccupiedthreshold attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -900,6 +1606,65 @@ class OccupancySensingCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -938,6 +1703,65 @@ class OccupancySensingCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -976,6 +1800,63 @@ class OccupancySensingCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1014,6 +1895,63 @@ class OccupancySensingCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1045,6 +1983,56 @@ class OccupancySensingCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1076,6 +2064,58 @@ class OccupancySensingCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OccupancySensingCluster::class.java.name) const val CLUSTER_ID: UInt = 1030u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OnOffCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OnOffCluster.kt index 7b3b700048da5e..b0801165c6d93c 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OnOffCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OnOffCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -39,14 +46,54 @@ import matter.tlv.TlvWriter class OnOffCluster(private val controller: MatterController, private val endpointId: UShort) { class StartUpOnOffAttribute(val value: UByte?) + sealed class StartUpOnOffAttributeSubscriptionState { + data class Success(val value: UByte?) : StartUpOnOffAttributeSubscriptionState() + + data class Error(val exception: Exception) : StartUpOnOffAttributeSubscriptionState() + + object SubscriptionEstablished : StartUpOnOffAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun off(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -210,6 +257,56 @@ class OnOffCluster(private val controller: MatterController, private val endpoin return decodedValue } + suspend fun subscribeOnOffAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Onoff attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGlobalSceneControlAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 16384u @@ -246,6 +343,63 @@ class OnOffCluster(private val controller: MatterController, private val endpoin return decodedValue } + suspend fun subscribeGlobalSceneControlAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16384u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Globalscenecontrol attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnTimeAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16385u @@ -322,6 +476,61 @@ class OnOffCluster(private val controller: MatterController, private val endpoin } } + suspend fun subscribeOnTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16385u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Ontime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOffWaitTimeAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16386u @@ -398,6 +607,61 @@ class OnOffCluster(private val controller: MatterController, private val endpoin } } + suspend fun subscribeOffWaitTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16386u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Offwaittime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartUpOnOffAttribute(): StartUpOnOffAttribute { val ATTRIBUTE_ID: UInt = 16387u @@ -479,6 +743,66 @@ class OnOffCluster(private val controller: MatterController, private val endpoin } } + suspend fun subscribeStartUpOnOffAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16387u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StartUpOnOffAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Startuponoff attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StartUpOnOffAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StartUpOnOffAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -517,6 +841,65 @@ class OnOffCluster(private val controller: MatterController, private val endpoin return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -555,6 +938,65 @@ class OnOffCluster(private val controller: MatterController, private val endpoin return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -593,6 +1035,63 @@ class OnOffCluster(private val controller: MatterController, private val endpoin return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -631,6 +1130,63 @@ class OnOffCluster(private val controller: MatterController, private val endpoin return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -662,6 +1218,56 @@ class OnOffCluster(private val controller: MatterController, private val endpoin return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -693,6 +1299,58 @@ class OnOffCluster(private val controller: MatterController, private val endpoin return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OnOffCluster::class.java.name) const val CLUSTER_ID: UInt = 6u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OnOffSwitchConfigurationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OnOffSwitchConfigurationCluster.kt index 7448ff847c1d43..7359a28163aae6 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OnOffSwitchConfigurationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OnOffSwitchConfigurationCluster.kt @@ -20,9 +20,16 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,12 +45,44 @@ class OnOffSwitchConfigurationCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readSwitchTypeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 0u @@ -75,6 +114,56 @@ class OnOffSwitchConfigurationCluster( return decodedValue } + suspend fun subscribeSwitchTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Switchtype attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSwitchActionsAttribute(): UByte { val ATTRIBUTE_ID: UInt = 16u @@ -146,6 +235,56 @@ class OnOffSwitchConfigurationCluster( } } + suspend fun subscribeSwitchActionsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Switchactions attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -184,6 +323,65 @@ class OnOffSwitchConfigurationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -222,6 +420,65 @@ class OnOffSwitchConfigurationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -260,6 +517,63 @@ class OnOffSwitchConfigurationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -298,6 +612,63 @@ class OnOffSwitchConfigurationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -329,6 +700,56 @@ class OnOffSwitchConfigurationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -360,6 +781,58 @@ class OnOffSwitchConfigurationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OnOffSwitchConfigurationCluster::class.java.name) const val CLUSTER_ID: UInt = 7u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OperationalCredentialsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OperationalCredentialsCluster.kt index 8f96cbccd13948..cfc1103e4216f4 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OperationalCredentialsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OperationalCredentialsCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -50,18 +57,78 @@ class OperationalCredentialsCluster( class NOCsAttribute(val value: List) + sealed class NOCsAttributeSubscriptionState { + data class Success(val value: List) : + NOCsAttributeSubscriptionState() + + data class Error(val exception: Exception) : NOCsAttributeSubscriptionState() + + object SubscriptionEstablished : NOCsAttributeSubscriptionState() + } + class FabricsAttribute(val value: List) + sealed class FabricsAttributeSubscriptionState { + data class Success(val value: List) : + FabricsAttributeSubscriptionState() + + data class Error(val exception: Exception) : FabricsAttributeSubscriptionState() + + object SubscriptionEstablished : FabricsAttributeSubscriptionState() + } + class TrustedRootCertificatesAttribute(val value: List) + sealed class TrustedRootCertificatesAttributeSubscriptionState { + data class Success(val value: List) : + TrustedRootCertificatesAttributeSubscriptionState() + + data class Error(val exception: Exception) : + TrustedRootCertificatesAttributeSubscriptionState() + + object SubscriptionEstablished : TrustedRootCertificatesAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun attestationRequest( attestationNonce: ByteArray, timedInvokeTimeout: Duration? = null @@ -631,6 +698,63 @@ class OperationalCredentialsCluster( return NOCsAttribute(decodedValue) } + suspend fun subscribeNOCsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NOCsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Nocs attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(OperationalCredentialsClusterNOCStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(NOCsAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(NOCsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFabricsAttribute(): FabricsAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -669,6 +793,68 @@ class OperationalCredentialsCluster( return FabricsAttribute(decodedValue) } + suspend fun subscribeFabricsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FabricsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Fabrics attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + OperationalCredentialsClusterFabricDescriptorStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + + emit(FabricsAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(FabricsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedFabricsAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -700,6 +886,58 @@ class OperationalCredentialsCluster( return decodedValue } + suspend fun subscribeSupportedFabricsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedfabrics attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCommissionedFabricsAttribute(): UByte { val ATTRIBUTE_ID: UInt = 3u @@ -731,6 +969,58 @@ class OperationalCredentialsCluster( return decodedValue } + suspend fun subscribeCommissionedFabricsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Commissionedfabrics attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTrustedRootCertificatesAttribute(): TrustedRootCertificatesAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -769,6 +1059,65 @@ class OperationalCredentialsCluster( return TrustedRootCertificatesAttribute(decodedValue) } + suspend fun subscribeTrustedRootCertificatesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TrustedRootCertificatesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Trustedrootcertificates attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getByteArray(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(TrustedRootCertificatesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(TrustedRootCertificatesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentFabricIndexAttribute(): UByte { val ATTRIBUTE_ID: UInt = 5u @@ -800,6 +1149,58 @@ class OperationalCredentialsCluster( return decodedValue } + suspend fun subscribeCurrentFabricIndexAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentfabricindex attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -838,6 +1239,65 @@ class OperationalCredentialsCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -876,6 +1336,65 @@ class OperationalCredentialsCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -914,6 +1433,63 @@ class OperationalCredentialsCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -952,6 +1528,63 @@ class OperationalCredentialsCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -983,6 +1616,56 @@ class OperationalCredentialsCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1014,6 +1697,58 @@ class OperationalCredentialsCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OperationalCredentialsCluster::class.java.name) const val CLUSTER_ID: UInt = 62u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OperationalStateCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OperationalStateCluster.kt index 82671e7f1c6083..68dd297ecea977 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OperationalStateCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OperationalStateCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -43,24 +50,98 @@ class OperationalStateCluster( class PhaseListAttribute(val value: List?) + sealed class PhaseListAttributeSubscriptionState { + data class Success(val value: List?) : PhaseListAttributeSubscriptionState() + + data class Error(val exception: Exception) : PhaseListAttributeSubscriptionState() + + object SubscriptionEstablished : PhaseListAttributeSubscriptionState() + } + class CurrentPhaseAttribute(val value: UByte?) + sealed class CurrentPhaseAttributeSubscriptionState { + data class Success(val value: UByte?) : CurrentPhaseAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentPhaseAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentPhaseAttributeSubscriptionState() + } + class CountdownTimeAttribute(val value: UInt?) + sealed class CountdownTimeAttributeSubscriptionState { + data class Success(val value: UInt?) : CountdownTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : CountdownTimeAttributeSubscriptionState() + + object SubscriptionEstablished : CountdownTimeAttributeSubscriptionState() + } + class OperationalStateListAttribute( val value: List ) + sealed class OperationalStateListAttributeSubscriptionState { + data class Success(val value: List) : + OperationalStateListAttributeSubscriptionState() + + data class Error(val exception: Exception) : OperationalStateListAttributeSubscriptionState() + + object SubscriptionEstablished : OperationalStateListAttributeSubscriptionState() + } + class OperationalErrorAttribute(val value: OperationalStateClusterErrorStateStruct) + sealed class OperationalErrorAttributeSubscriptionState { + data class Success(val value: OperationalStateClusterErrorStateStruct) : + OperationalErrorAttributeSubscriptionState() + + data class Error(val exception: Exception) : OperationalErrorAttributeSubscriptionState() + + object SubscriptionEstablished : OperationalErrorAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun pause(timedInvokeTimeout: Duration? = null): OperationalCommandResponse { val commandId: UInt = 0u @@ -272,6 +353,68 @@ class OperationalStateCluster( return PhaseListAttribute(decodedValue) } + suspend fun subscribePhaseListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PhaseListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Phaselist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (!tlvReader.isNull()) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getString(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PhaseListAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PhaseListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPhaseAttribute(): CurrentPhaseAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -309,6 +452,62 @@ class OperationalStateCluster( return CurrentPhaseAttribute(decodedValue) } + suspend fun subscribeCurrentPhaseAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentPhaseAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentphase attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentPhaseAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentPhaseAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCountdownTimeAttribute(): CountdownTimeAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -350,6 +549,66 @@ class OperationalStateCluster( return CountdownTimeAttribute(decodedValue) } + suspend fun subscribeCountdownTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CountdownTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Countdowntime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CountdownTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CountdownTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalStateListAttribute(): OperationalStateListAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -388,6 +647,65 @@ class OperationalStateCluster( return OperationalStateListAttribute(decodedValue) } + suspend fun subscribeOperationalStateListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OperationalStateListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalstatelist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(OperationalStateClusterOperationalStateStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(OperationalStateListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(OperationalStateListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalStateAttribute(): UByte { val ATTRIBUTE_ID: UInt = 4u @@ -419,6 +737,58 @@ class OperationalStateCluster( return decodedValue } + suspend fun subscribeOperationalStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalstate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalErrorAttribute(): OperationalErrorAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -451,6 +821,59 @@ class OperationalStateCluster( return OperationalErrorAttribute(decodedValue) } + suspend fun subscribeOperationalErrorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OperationalErrorAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalerror attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: OperationalStateClusterErrorStateStruct = + OperationalStateClusterErrorStateStruct.fromTlv(AnonymousTag, tlvReader) + + emit(OperationalErrorAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(OperationalErrorAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -489,6 +912,65 @@ class OperationalStateCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -527,6 +1009,65 @@ class OperationalStateCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -565,6 +1106,63 @@ class OperationalStateCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -603,6 +1201,63 @@ class OperationalStateCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -634,6 +1289,56 @@ class OperationalStateCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -665,6 +1370,58 @@ class OperationalStateCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OperationalStateCluster::class.java.name) const val CLUSTER_ID: UInt = 96u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OtaSoftwareUpdateProviderCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OtaSoftwareUpdateProviderCluster.kt index 83c5b1a11a375c..5f109918016959 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OtaSoftwareUpdateProviderCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OtaSoftwareUpdateProviderCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -52,12 +58,44 @@ class OtaSoftwareUpdateProviderCluster( class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun queryImage( vendorID: UShort, productID: UShort, @@ -399,6 +437,65 @@ class OtaSoftwareUpdateProviderCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -437,6 +534,65 @@ class OtaSoftwareUpdateProviderCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -475,6 +631,63 @@ class OtaSoftwareUpdateProviderCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -513,6 +726,63 @@ class OtaSoftwareUpdateProviderCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -544,6 +814,56 @@ class OtaSoftwareUpdateProviderCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -575,6 +895,58 @@ class OtaSoftwareUpdateProviderCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OtaSoftwareUpdateProviderCluster::class.java.name) const val CLUSTER_ID: UInt = 41u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OtaSoftwareUpdateRequestorCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OtaSoftwareUpdateRequestorCluster.kt index ff7f35ac10a4ee..35f2a59e30fac9 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OtaSoftwareUpdateRequestorCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OtaSoftwareUpdateRequestorCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -44,16 +52,65 @@ class OtaSoftwareUpdateRequestorCluster( val value: List ) + sealed class DefaultOTAProvidersAttributeSubscriptionState { + data class Success(val value: List) : + DefaultOTAProvidersAttributeSubscriptionState() + + data class Error(val exception: Exception) : DefaultOTAProvidersAttributeSubscriptionState() + + object SubscriptionEstablished : DefaultOTAProvidersAttributeSubscriptionState() + } + class UpdateStateProgressAttribute(val value: UByte?) + sealed class UpdateStateProgressAttributeSubscriptionState { + data class Success(val value: UByte?) : UpdateStateProgressAttributeSubscriptionState() + + data class Error(val exception: Exception) : UpdateStateProgressAttributeSubscriptionState() + + object SubscriptionEstablished : UpdateStateProgressAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun announceOTAProvider( providerNodeID: ULong, vendorID: UShort, @@ -181,6 +238,67 @@ class OtaSoftwareUpdateRequestorCluster( } } + suspend fun subscribeDefaultOTAProvidersAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DefaultOTAProvidersAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Defaultotaproviders attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + OtaSoftwareUpdateRequestorClusterProviderLocation.fromTlv(AnonymousTag, tlvReader) + ) + } + tlvReader.exitContainer() + } + + emit(DefaultOTAProvidersAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(DefaultOTAProvidersAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUpdatePossibleAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 1u @@ -212,6 +330,58 @@ class OtaSoftwareUpdateRequestorCluster( return decodedValue } + suspend fun subscribeUpdatePossibleAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Updatepossible attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUpdateStateAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -243,6 +413,56 @@ class OtaSoftwareUpdateRequestorCluster( return decodedValue } + suspend fun subscribeUpdateStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Updatestate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUpdateStateProgressAttribute(): UpdateStateProgressAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -280,6 +500,64 @@ class OtaSoftwareUpdateRequestorCluster( return UpdateStateProgressAttribute(decodedValue) } + suspend fun subscribeUpdateStateProgressAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UpdateStateProgressAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Updatestateprogress attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(UpdateStateProgressAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UpdateStateProgressAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -318,6 +596,65 @@ class OtaSoftwareUpdateRequestorCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -356,6 +693,65 @@ class OtaSoftwareUpdateRequestorCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -394,6 +790,63 @@ class OtaSoftwareUpdateRequestorCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -432,6 +885,63 @@ class OtaSoftwareUpdateRequestorCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -463,6 +973,56 @@ class OtaSoftwareUpdateRequestorCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -494,6 +1054,58 @@ class OtaSoftwareUpdateRequestorCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OtaSoftwareUpdateRequestorCluster::class.java.name) const val CLUSTER_ID: UInt = 42u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OvenCavityOperationalStateCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OvenCavityOperationalStateCluster.kt index 3a126cfd15c79d..86aeb3500ceee6 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OvenCavityOperationalStateCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OvenCavityOperationalStateCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -43,24 +50,98 @@ class OvenCavityOperationalStateCluster( class PhaseListAttribute(val value: List?) + sealed class PhaseListAttributeSubscriptionState { + data class Success(val value: List?) : PhaseListAttributeSubscriptionState() + + data class Error(val exception: Exception) : PhaseListAttributeSubscriptionState() + + object SubscriptionEstablished : PhaseListAttributeSubscriptionState() + } + class CurrentPhaseAttribute(val value: UByte?) + sealed class CurrentPhaseAttributeSubscriptionState { + data class Success(val value: UByte?) : CurrentPhaseAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentPhaseAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentPhaseAttributeSubscriptionState() + } + class CountdownTimeAttribute(val value: UInt?) + sealed class CountdownTimeAttributeSubscriptionState { + data class Success(val value: UInt?) : CountdownTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : CountdownTimeAttributeSubscriptionState() + + object SubscriptionEstablished : CountdownTimeAttributeSubscriptionState() + } + class OperationalStateListAttribute( val value: List ) + sealed class OperationalStateListAttributeSubscriptionState { + data class Success(val value: List) : + OperationalStateListAttributeSubscriptionState() + + data class Error(val exception: Exception) : OperationalStateListAttributeSubscriptionState() + + object SubscriptionEstablished : OperationalStateListAttributeSubscriptionState() + } + class OperationalErrorAttribute(val value: OvenCavityOperationalStateClusterErrorStateStruct) + sealed class OperationalErrorAttributeSubscriptionState { + data class Success(val value: OvenCavityOperationalStateClusterErrorStateStruct) : + OperationalErrorAttributeSubscriptionState() + + data class Error(val exception: Exception) : OperationalErrorAttributeSubscriptionState() + + object SubscriptionEstablished : OperationalErrorAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun pause(timedInvokeTimeout: Duration? = null): OperationalCommandResponse { val commandId: UInt = 0u @@ -272,6 +353,68 @@ class OvenCavityOperationalStateCluster( return PhaseListAttribute(decodedValue) } + suspend fun subscribePhaseListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PhaseListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Phaselist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (!tlvReader.isNull()) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getString(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PhaseListAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PhaseListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPhaseAttribute(): CurrentPhaseAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -309,6 +452,62 @@ class OvenCavityOperationalStateCluster( return CurrentPhaseAttribute(decodedValue) } + suspend fun subscribeCurrentPhaseAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentPhaseAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentphase attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentPhaseAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentPhaseAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCountdownTimeAttribute(): CountdownTimeAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -350,6 +549,66 @@ class OvenCavityOperationalStateCluster( return CountdownTimeAttribute(decodedValue) } + suspend fun subscribeCountdownTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CountdownTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Countdowntime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CountdownTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CountdownTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalStateListAttribute(): OperationalStateListAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -390,6 +649,70 @@ class OvenCavityOperationalStateCluster( return OperationalStateListAttribute(decodedValue) } + suspend fun subscribeOperationalStateListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OperationalStateListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalstatelist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + OvenCavityOperationalStateClusterOperationalStateStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + + emit(OperationalStateListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(OperationalStateListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalStateAttribute(): UByte { val ATTRIBUTE_ID: UInt = 4u @@ -421,6 +744,58 @@ class OvenCavityOperationalStateCluster( return decodedValue } + suspend fun subscribeOperationalStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalstate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalErrorAttribute(): OperationalErrorAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -453,6 +828,59 @@ class OvenCavityOperationalStateCluster( return OperationalErrorAttribute(decodedValue) } + suspend fun subscribeOperationalErrorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OperationalErrorAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalerror attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: OvenCavityOperationalStateClusterErrorStateStruct = + OvenCavityOperationalStateClusterErrorStateStruct.fromTlv(AnonymousTag, tlvReader) + + emit(OperationalErrorAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(OperationalErrorAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -491,6 +919,65 @@ class OvenCavityOperationalStateCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -529,6 +1016,65 @@ class OvenCavityOperationalStateCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -567,6 +1113,63 @@ class OvenCavityOperationalStateCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -605,6 +1208,63 @@ class OvenCavityOperationalStateCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -636,6 +1296,56 @@ class OvenCavityOperationalStateCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -667,6 +1377,58 @@ class OvenCavityOperationalStateCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OvenCavityOperationalStateCluster::class.java.name) const val CLUSTER_ID: UInt = 72u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OvenModeCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OvenModeCluster.kt index aa0be94f6d804b..8dcff4690b2aa5 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OvenModeCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OvenModeCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -41,18 +48,75 @@ class OvenModeCluster(private val controller: MatterController, private val endp class SupportedModesAttribute(val value: List) + sealed class SupportedModesAttributeSubscriptionState { + data class Success(val value: List) : + SupportedModesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedModesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedModesAttributeSubscriptionState() + } + class StartUpModeAttribute(val value: UByte?) + sealed class StartUpModeAttributeSubscriptionState { + data class Success(val value: UByte?) : StartUpModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : StartUpModeAttributeSubscriptionState() + + object SubscriptionEstablished : StartUpModeAttributeSubscriptionState() + } + class OnModeAttribute(val value: UByte?) + sealed class OnModeAttributeSubscriptionState { + data class Success(val value: UByte?) : OnModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnModeAttributeSubscriptionState() + + object SubscriptionEstablished : OnModeAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun changeToMode( newMode: UByte, timedInvokeTimeout: Duration? = null @@ -155,6 +219,65 @@ class OvenModeCluster(private val controller: MatterController, private val endp return SupportedModesAttribute(decodedValue) } + suspend fun subscribeSupportedModesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedModesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedmodes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(OvenModeClusterModeOptionStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(SupportedModesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedModesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -186,6 +309,56 @@ class OvenModeCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeCurrentModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartUpModeAttribute(): StartUpModeAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -267,6 +440,66 @@ class OvenModeCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeStartUpModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StartUpModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Startupmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StartUpModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StartUpModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnModeAttribute(): OnModeAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -348,6 +581,66 @@ class OvenModeCluster(private val controller: MatterController, private val endp } } + suspend fun subscribeOnModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Onmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OnModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -386,6 +679,65 @@ class OvenModeCluster(private val controller: MatterController, private val endp return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -424,6 +776,65 @@ class OvenModeCluster(private val controller: MatterController, private val endp return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -462,6 +873,63 @@ class OvenModeCluster(private val controller: MatterController, private val endp return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -500,6 +968,63 @@ class OvenModeCluster(private val controller: MatterController, private val endp return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -531,6 +1056,56 @@ class OvenModeCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -562,6 +1137,58 @@ class OvenModeCluster(private val controller: MatterController, private val endp return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OvenModeCluster::class.java.name) const val CLUSTER_ID: UInt = 73u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/OzoneConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/OzoneConcentrationMeasurementCluster.kt index 2cc23fa5ba0257..c660d89a0f566c 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/OzoneConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/OzoneConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class OzoneConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class OzoneConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class OzoneConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class OzoneConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class OzoneConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class OzoneConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class OzoneConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class OzoneConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class OzoneConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class OzoneConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class OzoneConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class OzoneConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class OzoneConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class OzoneConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class OzoneConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class OzoneConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class OzoneConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class OzoneConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(OzoneConcentrationMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1045u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm10ConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm10ConcentrationMeasurementCluster.kt index a0fb883cb6f6a7..d81ab6b7f6574d 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm10ConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm10ConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class Pm10ConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class Pm10ConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class Pm10ConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class Pm10ConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class Pm10ConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class Pm10ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class Pm10ConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class Pm10ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class Pm10ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class Pm10ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class Pm10ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class Pm10ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class Pm10ConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class Pm10ConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class Pm10ConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class Pm10ConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class Pm10ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class Pm10ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(Pm10ConcentrationMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1069u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm1ConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm1ConcentrationMeasurementCluster.kt index 6ce088f31b6816..9f880bbbec52d7 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm1ConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm1ConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class Pm1ConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class Pm1ConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class Pm1ConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class Pm1ConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class Pm1ConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class Pm1ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class Pm1ConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class Pm1ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class Pm1ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class Pm1ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class Pm1ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class Pm1ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class Pm1ConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class Pm1ConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class Pm1ConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class Pm1ConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class Pm1ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class Pm1ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(Pm1ConcentrationMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1068u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm25ConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm25ConcentrationMeasurementCluster.kt index a09517acf21508..cfd4cda6106049 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm25ConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/Pm25ConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class Pm25ConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class Pm25ConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class Pm25ConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class Pm25ConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class Pm25ConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class Pm25ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class Pm25ConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class Pm25ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class Pm25ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class Pm25ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class Pm25ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class Pm25ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class Pm25ConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class Pm25ConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class Pm25ConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class Pm25ConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class Pm25ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class Pm25ConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(Pm25ConcentrationMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1066u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/PowerSourceCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/PowerSourceCluster.kt index f701ae91a1a006..e5df8e8e29a31d 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/PowerSourceCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/PowerSourceCluster.kt @@ -17,11 +17,21 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -30,36 +40,167 @@ import matter.tlv.TlvReader class PowerSourceCluster(private val controller: MatterController, private val endpointId: UShort) { class WiredAssessedInputVoltageAttribute(val value: UInt?) + sealed class WiredAssessedInputVoltageAttributeSubscriptionState { + data class Success(val value: UInt?) : WiredAssessedInputVoltageAttributeSubscriptionState() + + data class Error(val exception: Exception) : + WiredAssessedInputVoltageAttributeSubscriptionState() + + object SubscriptionEstablished : WiredAssessedInputVoltageAttributeSubscriptionState() + } + class WiredAssessedInputFrequencyAttribute(val value: UShort?) + sealed class WiredAssessedInputFrequencyAttributeSubscriptionState { + data class Success(val value: UShort?) : + WiredAssessedInputFrequencyAttributeSubscriptionState() + + data class Error(val exception: Exception) : + WiredAssessedInputFrequencyAttributeSubscriptionState() + + object SubscriptionEstablished : WiredAssessedInputFrequencyAttributeSubscriptionState() + } + class WiredAssessedCurrentAttribute(val value: UInt?) + sealed class WiredAssessedCurrentAttributeSubscriptionState { + data class Success(val value: UInt?) : WiredAssessedCurrentAttributeSubscriptionState() + + data class Error(val exception: Exception) : WiredAssessedCurrentAttributeSubscriptionState() + + object SubscriptionEstablished : WiredAssessedCurrentAttributeSubscriptionState() + } + class ActiveWiredFaultsAttribute(val value: List?) + sealed class ActiveWiredFaultsAttributeSubscriptionState { + data class Success(val value: List?) : ActiveWiredFaultsAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveWiredFaultsAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveWiredFaultsAttributeSubscriptionState() + } + class BatVoltageAttribute(val value: UInt?) + sealed class BatVoltageAttributeSubscriptionState { + data class Success(val value: UInt?) : BatVoltageAttributeSubscriptionState() + + data class Error(val exception: Exception) : BatVoltageAttributeSubscriptionState() + + object SubscriptionEstablished : BatVoltageAttributeSubscriptionState() + } + class BatPercentRemainingAttribute(val value: UByte?) + sealed class BatPercentRemainingAttributeSubscriptionState { + data class Success(val value: UByte?) : BatPercentRemainingAttributeSubscriptionState() + + data class Error(val exception: Exception) : BatPercentRemainingAttributeSubscriptionState() + + object SubscriptionEstablished : BatPercentRemainingAttributeSubscriptionState() + } + class BatTimeRemainingAttribute(val value: UInt?) + sealed class BatTimeRemainingAttributeSubscriptionState { + data class Success(val value: UInt?) : BatTimeRemainingAttributeSubscriptionState() + + data class Error(val exception: Exception) : BatTimeRemainingAttributeSubscriptionState() + + object SubscriptionEstablished : BatTimeRemainingAttributeSubscriptionState() + } + class ActiveBatFaultsAttribute(val value: List?) + sealed class ActiveBatFaultsAttributeSubscriptionState { + data class Success(val value: List?) : ActiveBatFaultsAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveBatFaultsAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveBatFaultsAttributeSubscriptionState() + } + class BatTimeToFullChargeAttribute(val value: UInt?) + sealed class BatTimeToFullChargeAttributeSubscriptionState { + data class Success(val value: UInt?) : BatTimeToFullChargeAttributeSubscriptionState() + + data class Error(val exception: Exception) : BatTimeToFullChargeAttributeSubscriptionState() + + object SubscriptionEstablished : BatTimeToFullChargeAttributeSubscriptionState() + } + class BatChargingCurrentAttribute(val value: UInt?) + sealed class BatChargingCurrentAttributeSubscriptionState { + data class Success(val value: UInt?) : BatChargingCurrentAttributeSubscriptionState() + + data class Error(val exception: Exception) : BatChargingCurrentAttributeSubscriptionState() + + object SubscriptionEstablished : BatChargingCurrentAttributeSubscriptionState() + } + class ActiveBatChargeFaultsAttribute(val value: List?) + sealed class ActiveBatChargeFaultsAttributeSubscriptionState { + data class Success(val value: List?) : ActiveBatChargeFaultsAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveBatChargeFaultsAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveBatChargeFaultsAttributeSubscriptionState() + } + class EndpointListAttribute(val value: List) + sealed class EndpointListAttributeSubscriptionState { + data class Success(val value: List) : EndpointListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EndpointListAttributeSubscriptionState() + + object SubscriptionEstablished : EndpointListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readStatusAttribute(): UByte { val ATTRIBUTE_ID: UInt = 0u @@ -91,6 +232,56 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Status attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOrderAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -122,6 +313,56 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeOrderAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Order attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDescriptionAttribute(): String { val ATTRIBUTE_ID: UInt = 2u @@ -153,6 +394,56 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeDescriptionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Description attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWiredAssessedInputVoltageAttribute(): WiredAssessedInputVoltageAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -194,6 +485,70 @@ class PowerSourceCluster(private val controller: MatterController, private val e return WiredAssessedInputVoltageAttribute(decodedValue) } + suspend fun subscribeWiredAssessedInputVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + WiredAssessedInputVoltageAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Wiredassessedinputvoltage attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(WiredAssessedInputVoltageAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(WiredAssessedInputVoltageAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWiredAssessedInputFrequencyAttribute(): WiredAssessedInputFrequencyAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -235,6 +590,70 @@ class PowerSourceCluster(private val controller: MatterController, private val e return WiredAssessedInputFrequencyAttribute(decodedValue) } + suspend fun subscribeWiredAssessedInputFrequencyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + WiredAssessedInputFrequencyAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Wiredassessedinputfrequency attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(WiredAssessedInputFrequencyAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(WiredAssessedInputFrequencyAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWiredCurrentTypeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 5u @@ -271,6 +690,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeWiredCurrentTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Wiredcurrenttype attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWiredAssessedCurrentAttribute(): WiredAssessedCurrentAttribute { val ATTRIBUTE_ID: UInt = 6u @@ -312,6 +788,68 @@ class PowerSourceCluster(private val controller: MatterController, private val e return WiredAssessedCurrentAttribute(decodedValue) } + suspend fun subscribeWiredAssessedCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + WiredAssessedCurrentAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Wiredassessedcurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(WiredAssessedCurrentAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(WiredAssessedCurrentAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWiredNominalVoltageAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 7u @@ -348,6 +886,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeWiredNominalVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Wirednominalvoltage attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWiredMaximumCurrentAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 8u @@ -384,6 +979,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeWiredMaximumCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Wiredmaximumcurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWiredPresentAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 9u @@ -420,6 +1072,61 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeWiredPresentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Wiredpresent attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveWiredFaultsAttribute(): ActiveWiredFaultsAttribute { val ATTRIBUTE_ID: UInt = 10u @@ -462,6 +1169,69 @@ class PowerSourceCluster(private val controller: MatterController, private val e return ActiveWiredFaultsAttribute(decodedValue) } + suspend fun subscribeActiveWiredFaultsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveWiredFaultsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activewiredfaults attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ActiveWiredFaultsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveWiredFaultsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatVoltageAttribute(): BatVoltageAttribute { val ATTRIBUTE_ID: UInt = 11u @@ -503,6 +1273,66 @@ class PowerSourceCluster(private val controller: MatterController, private val e return BatVoltageAttribute(decodedValue) } + suspend fun subscribeBatVoltageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BatVoltageAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Batvoltage attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BatVoltageAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BatVoltageAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatPercentRemainingAttribute(): BatPercentRemainingAttribute { val ATTRIBUTE_ID: UInt = 12u @@ -544,6 +1374,68 @@ class PowerSourceCluster(private val controller: MatterController, private val e return BatPercentRemainingAttribute(decodedValue) } + suspend fun subscribeBatPercentRemainingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BatPercentRemainingAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batpercentremaining attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BatPercentRemainingAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BatPercentRemainingAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatTimeRemainingAttribute(): BatTimeRemainingAttribute { val ATTRIBUTE_ID: UInt = 13u @@ -585,6 +1477,68 @@ class PowerSourceCluster(private val controller: MatterController, private val e return BatTimeRemainingAttribute(decodedValue) } + suspend fun subscribeBatTimeRemainingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 13u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BatTimeRemainingAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Battimeremaining attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BatTimeRemainingAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BatTimeRemainingAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatChargeLevelAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 14u @@ -621,6 +1575,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatChargeLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 14u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batchargelevel attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatReplacementNeededAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 15u @@ -657,6 +1668,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatReplacementNeededAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 15u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batreplacementneeded attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatReplaceabilityAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 16u @@ -693,6 +1761,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatReplaceabilityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batreplaceability attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatPresentAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 17u @@ -729,6 +1854,61 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatPresentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Batpresent attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveBatFaultsAttribute(): ActiveBatFaultsAttribute { val ATTRIBUTE_ID: UInt = 18u @@ -771,6 +1951,69 @@ class PowerSourceCluster(private val controller: MatterController, private val e return ActiveBatFaultsAttribute(decodedValue) } + suspend fun subscribeActiveBatFaultsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveBatFaultsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activebatfaults attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ActiveBatFaultsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveBatFaultsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatReplacementDescriptionAttribute(): String? { val ATTRIBUTE_ID: UInt = 19u @@ -807,6 +2050,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatReplacementDescriptionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batreplacementdescription attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatCommonDesignationAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 20u @@ -843,6 +2143,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatCommonDesignationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batcommondesignation attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatANSIDesignationAttribute(): String? { val ATTRIBUTE_ID: UInt = 21u @@ -879,6 +2236,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatANSIDesignationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 21u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batansidesignation attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatIECDesignationAttribute(): String? { val ATTRIBUTE_ID: UInt = 22u @@ -915,6 +2329,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatIECDesignationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 22u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batiecdesignation attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatApprovedChemistryAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 23u @@ -951,6 +2422,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatApprovedChemistryAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 23u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batapprovedchemistry attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatCapacityAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 24u @@ -987,6 +2515,61 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatCapacityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 24u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Batcapacity attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatQuantityAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 25u @@ -1023,6 +2606,61 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatQuantityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 25u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Batquantity attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatChargeStateAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 26u @@ -1059,6 +2697,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatChargeStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 26u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batchargestate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatTimeToFullChargeAttribute(): BatTimeToFullChargeAttribute { val ATTRIBUTE_ID: UInt = 27u @@ -1100,6 +2795,68 @@ class PowerSourceCluster(private val controller: MatterController, private val e return BatTimeToFullChargeAttribute(decodedValue) } + suspend fun subscribeBatTimeToFullChargeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 27u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BatTimeToFullChargeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Battimetofullcharge attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BatTimeToFullChargeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BatTimeToFullChargeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatFunctionalWhileChargingAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 28u @@ -1136,6 +2893,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeBatFunctionalWhileChargingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 28u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batfunctionalwhilecharging attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatChargingCurrentAttribute(): BatChargingCurrentAttribute { val ATTRIBUTE_ID: UInt = 29u @@ -1177,6 +2991,68 @@ class PowerSourceCluster(private val controller: MatterController, private val e return BatChargingCurrentAttribute(decodedValue) } + suspend fun subscribeBatChargingCurrentAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 29u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BatChargingCurrentAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Batchargingcurrent attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BatChargingCurrentAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BatChargingCurrentAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveBatChargeFaultsAttribute(): ActiveBatChargeFaultsAttribute { val ATTRIBUTE_ID: UInt = 30u @@ -1219,6 +3095,69 @@ class PowerSourceCluster(private val controller: MatterController, private val e return ActiveBatChargeFaultsAttribute(decodedValue) } + suspend fun subscribeActiveBatChargeFaultsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 30u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveBatChargeFaultsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activebatchargefaults attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ActiveBatChargeFaultsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveBatChargeFaultsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEndpointListAttribute(): EndpointListAttribute { val ATTRIBUTE_ID: UInt = 31u @@ -1257,6 +3196,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return EndpointListAttribute(decodedValue) } + suspend fun subscribeEndpointListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 31u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EndpointListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Endpointlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUShort(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EndpointListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EndpointListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1295,6 +3291,65 @@ class PowerSourceCluster(private val controller: MatterController, private val e return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1333,6 +3388,65 @@ class PowerSourceCluster(private val controller: MatterController, private val e return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1371,6 +3485,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1409,6 +3580,63 @@ class PowerSourceCluster(private val controller: MatterController, private val e return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1440,6 +3668,56 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1471,6 +3749,58 @@ class PowerSourceCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(PowerSourceCluster::class.java.name) const val CLUSTER_ID: UInt = 47u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/PowerSourceConfigurationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/PowerSourceConfigurationCluster.kt index efd82e8a519fc7..eb3b505f117912 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/PowerSourceConfigurationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/PowerSourceConfigurationCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,14 +40,54 @@ class PowerSourceConfigurationCluster( ) { class SourcesAttribute(val value: List) + sealed class SourcesAttributeSubscriptionState { + data class Success(val value: List) : SourcesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SourcesAttributeSubscriptionState() + + object SubscriptionEstablished : SourcesAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readSourcesAttribute(): SourcesAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -79,6 +126,63 @@ class PowerSourceConfigurationCluster( return SourcesAttribute(decodedValue) } + suspend fun subscribeSourcesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SourcesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Sources attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUShort(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(SourcesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SourcesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -117,6 +221,65 @@ class PowerSourceConfigurationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -155,6 +318,65 @@ class PowerSourceConfigurationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -193,6 +415,63 @@ class PowerSourceConfigurationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -231,6 +510,63 @@ class PowerSourceConfigurationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -262,6 +598,56 @@ class PowerSourceConfigurationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -293,6 +679,58 @@ class PowerSourceConfigurationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(PowerSourceConfigurationCluster::class.java.name) const val CLUSTER_ID: UInt = 46u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/PressureMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/PressureMeasurementCluster.kt index 4d4ec17577fc6d..e374599a909987 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/PressureMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/PressureMeasurementCluster.kt @@ -17,11 +17,19 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.ByteSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,24 +41,104 @@ class PressureMeasurementCluster( ) { class MeasuredValueAttribute(val value: Short?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Short?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Short?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Short?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Short?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Short?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class ScaledValueAttribute(val value: Short?) + sealed class ScaledValueAttributeSubscriptionState { + data class Success(val value: Short?) : ScaledValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : ScaledValueAttributeSubscriptionState() + + object SubscriptionEstablished : ScaledValueAttributeSubscriptionState() + } + class MinScaledValueAttribute(val value: Short?) + sealed class MinScaledValueAttributeSubscriptionState { + data class Success(val value: Short?) : MinScaledValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinScaledValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinScaledValueAttributeSubscriptionState() + } + class MaxScaledValueAttribute(val value: Short?) + sealed class MaxScaledValueAttributeSubscriptionState { + data class Success(val value: Short?) : MaxScaledValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxScaledValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxScaledValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -88,6 +176,62 @@ class PressureMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -125,6 +269,64 @@ class PressureMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -162,6 +364,64 @@ class PressureMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readToleranceAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 3u @@ -198,6 +458,61 @@ class PressureMeasurementCluster( return decodedValue } + suspend fun subscribeToleranceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Tolerance attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readScaledValueAttribute(): ScaledValueAttribute { val ATTRIBUTE_ID: UInt = 16u @@ -239,6 +554,66 @@ class PressureMeasurementCluster( return ScaledValueAttribute(decodedValue) } + suspend fun subscribeScaledValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ScaledValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Scaledvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ScaledValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ScaledValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinScaledValueAttribute(): MinScaledValueAttribute { val ATTRIBUTE_ID: UInt = 17u @@ -280,6 +655,68 @@ class PressureMeasurementCluster( return MinScaledValueAttribute(decodedValue) } + suspend fun subscribeMinScaledValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinScaledValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minscaledvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinScaledValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinScaledValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxScaledValueAttribute(): MaxScaledValueAttribute { val ATTRIBUTE_ID: UInt = 18u @@ -321,6 +758,68 @@ class PressureMeasurementCluster( return MaxScaledValueAttribute(decodedValue) } + suspend fun subscribeMaxScaledValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxScaledValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxscaledvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxScaledValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxScaledValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readScaledToleranceAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 19u @@ -357,6 +856,63 @@ class PressureMeasurementCluster( return decodedValue } + suspend fun subscribeScaledToleranceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Scaledtolerance attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readScaleAttribute(): Byte? { val ATTRIBUTE_ID: UInt = 20u @@ -393,6 +949,61 @@ class PressureMeasurementCluster( return decodedValue } + suspend fun subscribeScaleAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Scale attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -431,6 +1042,65 @@ class PressureMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -469,6 +1139,65 @@ class PressureMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -507,6 +1236,63 @@ class PressureMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -545,6 +1331,63 @@ class PressureMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -576,6 +1419,56 @@ class PressureMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -607,6 +1500,58 @@ class PressureMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(PressureMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1027u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyConfigurationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyConfigurationCluster.kt index fbabea98973688..5eb0f105ba47d1 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyConfigurationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyConfigurationCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,12 +40,44 @@ class ProxyConfigurationCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -77,6 +116,65 @@ class ProxyConfigurationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -115,6 +213,65 @@ class ProxyConfigurationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -153,6 +310,63 @@ class ProxyConfigurationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -191,6 +405,63 @@ class ProxyConfigurationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -222,6 +493,56 @@ class ProxyConfigurationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -253,6 +574,58 @@ class ProxyConfigurationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ProxyConfigurationCluster::class.java.name) const val CLUSTER_ID: UInt = 66u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyDiscoveryCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyDiscoveryCluster.kt index e5f72cc56f44e6..46ad79a25cd0c2 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyDiscoveryCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyDiscoveryCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,12 +40,44 @@ class ProxyDiscoveryCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -77,6 +116,65 @@ class ProxyDiscoveryCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -115,6 +213,65 @@ class ProxyDiscoveryCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -153,6 +310,63 @@ class ProxyDiscoveryCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -191,6 +405,63 @@ class ProxyDiscoveryCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -222,6 +493,56 @@ class ProxyDiscoveryCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -253,6 +574,58 @@ class ProxyDiscoveryCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ProxyDiscoveryCluster::class.java.name) const val CLUSTER_ID: UInt = 67u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyValidCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyValidCluster.kt index 26764e35031074..96d846ad277cec 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyValidCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ProxyValidCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -30,12 +37,44 @@ import matter.tlv.TlvReader class ProxyValidCluster(private val controller: MatterController, private val endpointId: UShort) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -74,6 +113,65 @@ class ProxyValidCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -112,6 +210,65 @@ class ProxyValidCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -150,6 +307,63 @@ class ProxyValidCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -188,6 +402,63 @@ class ProxyValidCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -219,6 +490,56 @@ class ProxyValidCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -250,6 +571,58 @@ class ProxyValidCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ProxyValidCluster::class.java.name) const val CLUSTER_ID: UInt = 68u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/PulseWidthModulationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/PulseWidthModulationCluster.kt index 822765f8c4f85a..0e2ffc820350d9 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/PulseWidthModulationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/PulseWidthModulationCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,12 +40,44 @@ class PulseWidthModulationCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -77,6 +116,65 @@ class PulseWidthModulationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -115,6 +213,65 @@ class PulseWidthModulationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -153,6 +310,63 @@ class PulseWidthModulationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -191,6 +405,63 @@ class PulseWidthModulationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -222,6 +493,56 @@ class PulseWidthModulationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -253,6 +574,58 @@ class PulseWidthModulationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(PulseWidthModulationCluster::class.java.name) const val CLUSTER_ID: UInt = 28u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/PumpConfigurationAndControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/PumpConfigurationAndControlCluster.kt index 966aa570f2f950..6620523d5be3fa 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/PumpConfigurationAndControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/PumpConfigurationAndControlCluster.kt @@ -20,9 +20,16 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,48 +45,224 @@ class PumpConfigurationAndControlCluster( ) { class MaxPressureAttribute(val value: Short?) + sealed class MaxPressureAttributeSubscriptionState { + data class Success(val value: Short?) : MaxPressureAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxPressureAttributeSubscriptionState() + + object SubscriptionEstablished : MaxPressureAttributeSubscriptionState() + } + class MaxSpeedAttribute(val value: UShort?) + sealed class MaxSpeedAttributeSubscriptionState { + data class Success(val value: UShort?) : MaxSpeedAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxSpeedAttributeSubscriptionState() + + object SubscriptionEstablished : MaxSpeedAttributeSubscriptionState() + } + class MaxFlowAttribute(val value: UShort?) + sealed class MaxFlowAttributeSubscriptionState { + data class Success(val value: UShort?) : MaxFlowAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxFlowAttributeSubscriptionState() + + object SubscriptionEstablished : MaxFlowAttributeSubscriptionState() + } + class MinConstPressureAttribute(val value: Short?) + sealed class MinConstPressureAttributeSubscriptionState { + data class Success(val value: Short?) : MinConstPressureAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinConstPressureAttributeSubscriptionState() + + object SubscriptionEstablished : MinConstPressureAttributeSubscriptionState() + } + class MaxConstPressureAttribute(val value: Short?) + sealed class MaxConstPressureAttributeSubscriptionState { + data class Success(val value: Short?) : MaxConstPressureAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxConstPressureAttributeSubscriptionState() + + object SubscriptionEstablished : MaxConstPressureAttributeSubscriptionState() + } + class MinCompPressureAttribute(val value: Short?) + sealed class MinCompPressureAttributeSubscriptionState { + data class Success(val value: Short?) : MinCompPressureAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinCompPressureAttributeSubscriptionState() + + object SubscriptionEstablished : MinCompPressureAttributeSubscriptionState() + } + class MaxCompPressureAttribute(val value: Short?) + sealed class MaxCompPressureAttributeSubscriptionState { + data class Success(val value: Short?) : MaxCompPressureAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxCompPressureAttributeSubscriptionState() + + object SubscriptionEstablished : MaxCompPressureAttributeSubscriptionState() + } + class MinConstSpeedAttribute(val value: UShort?) + sealed class MinConstSpeedAttributeSubscriptionState { + data class Success(val value: UShort?) : MinConstSpeedAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinConstSpeedAttributeSubscriptionState() + + object SubscriptionEstablished : MinConstSpeedAttributeSubscriptionState() + } + class MaxConstSpeedAttribute(val value: UShort?) + sealed class MaxConstSpeedAttributeSubscriptionState { + data class Success(val value: UShort?) : MaxConstSpeedAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxConstSpeedAttributeSubscriptionState() + + object SubscriptionEstablished : MaxConstSpeedAttributeSubscriptionState() + } + class MinConstFlowAttribute(val value: UShort?) + sealed class MinConstFlowAttributeSubscriptionState { + data class Success(val value: UShort?) : MinConstFlowAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinConstFlowAttributeSubscriptionState() + + object SubscriptionEstablished : MinConstFlowAttributeSubscriptionState() + } + class MaxConstFlowAttribute(val value: UShort?) + sealed class MaxConstFlowAttributeSubscriptionState { + data class Success(val value: UShort?) : MaxConstFlowAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxConstFlowAttributeSubscriptionState() + + object SubscriptionEstablished : MaxConstFlowAttributeSubscriptionState() + } + class MinConstTempAttribute(val value: Short?) + sealed class MinConstTempAttributeSubscriptionState { + data class Success(val value: Short?) : MinConstTempAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinConstTempAttributeSubscriptionState() + + object SubscriptionEstablished : MinConstTempAttributeSubscriptionState() + } + class MaxConstTempAttribute(val value: Short?) + sealed class MaxConstTempAttributeSubscriptionState { + data class Success(val value: Short?) : MaxConstTempAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxConstTempAttributeSubscriptionState() + + object SubscriptionEstablished : MaxConstTempAttributeSubscriptionState() + } + class CapacityAttribute(val value: Short?) + sealed class CapacityAttributeSubscriptionState { + data class Success(val value: Short?) : CapacityAttributeSubscriptionState() + + data class Error(val exception: Exception) : CapacityAttributeSubscriptionState() + + object SubscriptionEstablished : CapacityAttributeSubscriptionState() + } + class SpeedAttribute(val value: UShort?) + sealed class SpeedAttributeSubscriptionState { + data class Success(val value: UShort?) : SpeedAttributeSubscriptionState() + + data class Error(val exception: Exception) : SpeedAttributeSubscriptionState() + + object SubscriptionEstablished : SpeedAttributeSubscriptionState() + } + class LifetimeRunningHoursAttribute(val value: UInt?) + sealed class LifetimeRunningHoursAttributeSubscriptionState { + data class Success(val value: UInt?) : LifetimeRunningHoursAttributeSubscriptionState() + + data class Error(val exception: Exception) : LifetimeRunningHoursAttributeSubscriptionState() + + object SubscriptionEstablished : LifetimeRunningHoursAttributeSubscriptionState() + } + class PowerAttribute(val value: UInt?) + sealed class PowerAttributeSubscriptionState { + data class Success(val value: UInt?) : PowerAttributeSubscriptionState() + + data class Error(val exception: Exception) : PowerAttributeSubscriptionState() + + object SubscriptionEstablished : PowerAttributeSubscriptionState() + } + class LifetimeEnergyConsumedAttribute(val value: UInt?) + sealed class LifetimeEnergyConsumedAttributeSubscriptionState { + data class Success(val value: UInt?) : LifetimeEnergyConsumedAttributeSubscriptionState() + + data class Error(val exception: Exception) : LifetimeEnergyConsumedAttributeSubscriptionState() + + object SubscriptionEstablished : LifetimeEnergyConsumedAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMaxPressureAttribute(): MaxPressureAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -117,6 +300,62 @@ class PumpConfigurationAndControlCluster( return MaxPressureAttribute(decodedValue) } + suspend fun subscribeMaxPressureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxPressureAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxpressure attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxPressureAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxPressureAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxSpeedAttribute(): MaxSpeedAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -154,6 +393,62 @@ class PumpConfigurationAndControlCluster( return MaxSpeedAttribute(decodedValue) } + suspend fun subscribeMaxSpeedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxSpeedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxspeed attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxSpeedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxSpeedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxFlowAttribute(): MaxFlowAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -191,6 +486,62 @@ class PumpConfigurationAndControlCluster( return MaxFlowAttribute(decodedValue) } + suspend fun subscribeMaxFlowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxFlowAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxflow attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxFlowAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxFlowAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinConstPressureAttribute(): MinConstPressureAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -232,6 +583,68 @@ class PumpConfigurationAndControlCluster( return MinConstPressureAttribute(decodedValue) } + suspend fun subscribeMinConstPressureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinConstPressureAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minconstpressure attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinConstPressureAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinConstPressureAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxConstPressureAttribute(): MaxConstPressureAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -273,6 +686,68 @@ class PumpConfigurationAndControlCluster( return MaxConstPressureAttribute(decodedValue) } + suspend fun subscribeMaxConstPressureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxConstPressureAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxconstpressure attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxConstPressureAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxConstPressureAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinCompPressureAttribute(): MinCompPressureAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -314,6 +789,68 @@ class PumpConfigurationAndControlCluster( return MinCompPressureAttribute(decodedValue) } + suspend fun subscribeMinCompPressureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinCompPressureAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Mincomppressure attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinCompPressureAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinCompPressureAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxCompPressureAttribute(): MaxCompPressureAttribute { val ATTRIBUTE_ID: UInt = 6u @@ -355,6 +892,68 @@ class PumpConfigurationAndControlCluster( return MaxCompPressureAttribute(decodedValue) } + suspend fun subscribeMaxCompPressureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxCompPressureAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxcomppressure attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxCompPressureAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxCompPressureAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinConstSpeedAttribute(): MinConstSpeedAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -396,6 +995,66 @@ class PumpConfigurationAndControlCluster( return MinConstSpeedAttribute(decodedValue) } + suspend fun subscribeMinConstSpeedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinConstSpeedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Minconstspeed attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinConstSpeedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinConstSpeedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxConstSpeedAttribute(): MaxConstSpeedAttribute { val ATTRIBUTE_ID: UInt = 8u @@ -437,6 +1096,66 @@ class PumpConfigurationAndControlCluster( return MaxConstSpeedAttribute(decodedValue) } + suspend fun subscribeMaxConstSpeedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxConstSpeedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxconstspeed attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxConstSpeedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxConstSpeedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinConstFlowAttribute(): MinConstFlowAttribute { val ATTRIBUTE_ID: UInt = 9u @@ -478,6 +1197,66 @@ class PumpConfigurationAndControlCluster( return MinConstFlowAttribute(decodedValue) } + suspend fun subscribeMinConstFlowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinConstFlowAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Minconstflow attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinConstFlowAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinConstFlowAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxConstFlowAttribute(): MaxConstFlowAttribute { val ATTRIBUTE_ID: UInt = 10u @@ -519,6 +1298,66 @@ class PumpConfigurationAndControlCluster( return MaxConstFlowAttribute(decodedValue) } + suspend fun subscribeMaxConstFlowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxConstFlowAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxconstflow attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxConstFlowAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxConstFlowAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinConstTempAttribute(): MinConstTempAttribute { val ATTRIBUTE_ID: UInt = 11u @@ -560,6 +1399,66 @@ class PumpConfigurationAndControlCluster( return MinConstTempAttribute(decodedValue) } + suspend fun subscribeMinConstTempAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinConstTempAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Minconsttemp attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinConstTempAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinConstTempAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxConstTempAttribute(): MaxConstTempAttribute { val ATTRIBUTE_ID: UInt = 12u @@ -601,6 +1500,66 @@ class PumpConfigurationAndControlCluster( return MaxConstTempAttribute(decodedValue) } + suspend fun subscribeMaxConstTempAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxConstTempAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Maxconsttemp attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxConstTempAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxConstTempAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPumpStatusAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16u @@ -637,6 +1596,61 @@ class PumpConfigurationAndControlCluster( return decodedValue } + suspend fun subscribePumpStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Pumpstatus attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEffectiveOperationModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 17u @@ -668,6 +1682,58 @@ class PumpConfigurationAndControlCluster( return decodedValue } + suspend fun subscribeEffectiveOperationModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Effectiveoperationmode attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEffectiveControlModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 18u @@ -699,6 +1765,58 @@ class PumpConfigurationAndControlCluster( return decodedValue } + suspend fun subscribeEffectiveControlModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Effectivecontrolmode attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCapacityAttribute(): CapacityAttribute { val ATTRIBUTE_ID: UInt = 19u @@ -736,6 +1854,62 @@ class PumpConfigurationAndControlCluster( return CapacityAttribute(decodedValue) } + suspend fun subscribeCapacityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CapacityAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Capacity attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CapacityAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CapacityAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSpeedAttribute(): SpeedAttribute { val ATTRIBUTE_ID: UInt = 20u @@ -777,6 +1951,66 @@ class PumpConfigurationAndControlCluster( return SpeedAttribute(decodedValue) } + suspend fun subscribeSpeedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SpeedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Speed attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SpeedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SpeedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLifetimeRunningHoursAttribute(): LifetimeRunningHoursAttribute { val ATTRIBUTE_ID: UInt = 21u @@ -858,6 +2092,68 @@ class PumpConfigurationAndControlCluster( } } + suspend fun subscribeLifetimeRunningHoursAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 21u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LifetimeRunningHoursAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lifetimerunninghours attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LifetimeRunningHoursAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LifetimeRunningHoursAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPowerAttribute(): PowerAttribute { val ATTRIBUTE_ID: UInt = 22u @@ -899,6 +2195,66 @@ class PumpConfigurationAndControlCluster( return PowerAttribute(decodedValue) } + suspend fun subscribePowerAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 22u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PowerAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Power attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PowerAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PowerAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLifetimeEnergyConsumedAttribute(): LifetimeEnergyConsumedAttribute { val ATTRIBUTE_ID: UInt = 23u @@ -983,6 +2339,68 @@ class PumpConfigurationAndControlCluster( } } + suspend fun subscribeLifetimeEnergyConsumedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 23u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LifetimeEnergyConsumedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lifetimeenergyconsumed attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LifetimeEnergyConsumedAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LifetimeEnergyConsumedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 32u @@ -1054,6 +2472,56 @@ class PumpConfigurationAndControlCluster( } } + suspend fun subscribeOperationModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 32u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Operationmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readControlModeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 33u @@ -1130,6 +2598,61 @@ class PumpConfigurationAndControlCluster( } } + suspend fun subscribeControlModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 33u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Controlmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1168,6 +2691,65 @@ class PumpConfigurationAndControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1206,6 +2788,65 @@ class PumpConfigurationAndControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1244,6 +2885,63 @@ class PumpConfigurationAndControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1282,6 +2980,63 @@ class PumpConfigurationAndControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1313,6 +3068,56 @@ class PumpConfigurationAndControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1344,6 +3149,58 @@ class PumpConfigurationAndControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(PumpConfigurationAndControlCluster::class.java.name) const val CLUSTER_ID: UInt = 512u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/RadonConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/RadonConcentrationMeasurementCluster.kt index adbb2c5b1bd3c5..d2d71369780de0 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/RadonConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/RadonConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class RadonConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class RadonConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class RadonConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class RadonConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class RadonConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class RadonConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class RadonConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class RadonConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class RadonConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class RadonConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class RadonConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class RadonConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class RadonConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class RadonConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class RadonConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class RadonConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class RadonConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class RadonConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(RadonConcentrationMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1071u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/RefrigeratorAlarmCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/RefrigeratorAlarmCluster.kt index 5a524b7b1de9bb..70eb72e6db7ec9 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/RefrigeratorAlarmCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/RefrigeratorAlarmCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,12 +40,44 @@ class RefrigeratorAlarmCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMaskAttribute(): UInt { val ATTRIBUTE_ID: UInt = 0u @@ -70,6 +109,56 @@ class RefrigeratorAlarmCluster( return decodedValue } + suspend fun subscribeMaskAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Mask attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStateAttribute(): UInt { val ATTRIBUTE_ID: UInt = 2u @@ -101,6 +190,56 @@ class RefrigeratorAlarmCluster( return decodedValue } + suspend fun subscribeStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "State attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedAttribute(): UInt { val ATTRIBUTE_ID: UInt = 3u @@ -132,6 +271,56 @@ class RefrigeratorAlarmCluster( return decodedValue } + suspend fun subscribeSupportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Supported attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -170,6 +359,65 @@ class RefrigeratorAlarmCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -208,6 +456,65 @@ class RefrigeratorAlarmCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -246,6 +553,63 @@ class RefrigeratorAlarmCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -284,6 +648,63 @@ class RefrigeratorAlarmCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -315,6 +736,56 @@ class RefrigeratorAlarmCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -346,6 +817,58 @@ class RefrigeratorAlarmCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(RefrigeratorAlarmCluster::class.java.name) const val CLUSTER_ID: UInt = 87u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/RefrigeratorAndTemperatureControlledCabinetModeCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/RefrigeratorAndTemperatureControlledCabinetModeCluster.kt index eda1f4a74607e6..61898b4f3d849d 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/RefrigeratorAndTemperatureControlledCabinetModeCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/RefrigeratorAndTemperatureControlledCabinetModeCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -46,18 +53,76 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( val value: List ) + sealed class SupportedModesAttributeSubscriptionState { + data class Success( + val value: List + ) : SupportedModesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedModesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedModesAttributeSubscriptionState() + } + class StartUpModeAttribute(val value: UByte?) + sealed class StartUpModeAttributeSubscriptionState { + data class Success(val value: UByte?) : StartUpModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : StartUpModeAttributeSubscriptionState() + + object SubscriptionEstablished : StartUpModeAttributeSubscriptionState() + } + class OnModeAttribute(val value: UByte?) + sealed class OnModeAttributeSubscriptionState { + data class Success(val value: UByte?) : OnModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnModeAttributeSubscriptionState() + + object SubscriptionEstablished : OnModeAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun changeToMode( newMode: UByte, timedInvokeTimeout: Duration? = null @@ -165,6 +230,71 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( return SupportedModesAttribute(decodedValue) } + suspend fun subscribeSupportedModesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedModesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedmodes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: + List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + RefrigeratorAndTemperatureControlledCabinetModeClusterModeOptionStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + + emit(SupportedModesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedModesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -196,6 +326,56 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( return decodedValue } + suspend fun subscribeCurrentModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartUpModeAttribute(): StartUpModeAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -277,6 +457,66 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( } } + suspend fun subscribeStartUpModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StartUpModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Startupmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StartUpModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StartUpModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnModeAttribute(): OnModeAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -358,6 +598,66 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( } } + suspend fun subscribeOnModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Onmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OnModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -396,6 +696,65 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -434,6 +793,65 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -472,6 +890,63 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -510,6 +985,63 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -541,6 +1073,56 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -572,6 +1154,58 @@ class RefrigeratorAndTemperatureControlledCabinetModeCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(RefrigeratorAndTemperatureControlledCabinetModeCluster::class.java.name) diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/RelativeHumidityMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/RelativeHumidityMeasurementCluster.kt index ac269f3eb80ce2..c8b35042a38183 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/RelativeHumidityMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/RelativeHumidityMeasurementCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,18 +40,74 @@ class RelativeHumidityMeasurementCluster( ) { class MeasuredValueAttribute(val value: UShort?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: UShort?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: UShort?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: UShort?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: UShort?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: UShort?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -82,6 +145,62 @@ class RelativeHumidityMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -119,6 +238,64 @@ class RelativeHumidityMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -156,6 +333,64 @@ class RelativeHumidityMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readToleranceAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 3u @@ -192,6 +427,61 @@ class RelativeHumidityMeasurementCluster( return decodedValue } + suspend fun subscribeToleranceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Tolerance attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -230,6 +520,65 @@ class RelativeHumidityMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -268,6 +617,65 @@ class RelativeHumidityMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -306,6 +714,63 @@ class RelativeHumidityMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -344,6 +809,63 @@ class RelativeHumidityMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -375,6 +897,56 @@ class RelativeHumidityMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -406,6 +978,58 @@ class RelativeHumidityMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(RelativeHumidityMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1029u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcCleanModeCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcCleanModeCluster.kt index a960aec6b98601..fc06787142bc87 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcCleanModeCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcCleanModeCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -44,16 +51,65 @@ class RvcCleanModeCluster( class SupportedModesAttribute(val value: List) + sealed class SupportedModesAttributeSubscriptionState { + data class Success(val value: List) : + SupportedModesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedModesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedModesAttributeSubscriptionState() + } + class OnModeAttribute(val value: UByte?) + sealed class OnModeAttributeSubscriptionState { + data class Success(val value: UByte?) : OnModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnModeAttributeSubscriptionState() + + object SubscriptionEstablished : OnModeAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun changeToMode( newMode: UByte, timedInvokeTimeout: Duration? = null @@ -156,6 +212,65 @@ class RvcCleanModeCluster( return SupportedModesAttribute(decodedValue) } + suspend fun subscribeSupportedModesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedModesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedmodes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(RvcCleanModeClusterModeOptionStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(SupportedModesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedModesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -187,6 +302,56 @@ class RvcCleanModeCluster( return decodedValue } + suspend fun subscribeCurrentModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnModeAttribute(): OnModeAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -268,6 +433,66 @@ class RvcCleanModeCluster( } } + suspend fun subscribeOnModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Onmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OnModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -306,6 +531,65 @@ class RvcCleanModeCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -344,6 +628,65 @@ class RvcCleanModeCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -382,6 +725,63 @@ class RvcCleanModeCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -420,6 +820,63 @@ class RvcCleanModeCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -451,6 +908,56 @@ class RvcCleanModeCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -482,6 +989,58 @@ class RvcCleanModeCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(RvcCleanModeCluster::class.java.name) const val CLUSTER_ID: UInt = 85u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcOperationalStateCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcOperationalStateCluster.kt index 399b9209825a6d..0513f78d1b0e38 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcOperationalStateCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcOperationalStateCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -43,24 +50,98 @@ class RvcOperationalStateCluster( class PhaseListAttribute(val value: List?) + sealed class PhaseListAttributeSubscriptionState { + data class Success(val value: List?) : PhaseListAttributeSubscriptionState() + + data class Error(val exception: Exception) : PhaseListAttributeSubscriptionState() + + object SubscriptionEstablished : PhaseListAttributeSubscriptionState() + } + class CurrentPhaseAttribute(val value: UByte?) + sealed class CurrentPhaseAttributeSubscriptionState { + data class Success(val value: UByte?) : CurrentPhaseAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentPhaseAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentPhaseAttributeSubscriptionState() + } + class CountdownTimeAttribute(val value: UInt?) + sealed class CountdownTimeAttributeSubscriptionState { + data class Success(val value: UInt?) : CountdownTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : CountdownTimeAttributeSubscriptionState() + + object SubscriptionEstablished : CountdownTimeAttributeSubscriptionState() + } + class OperationalStateListAttribute( val value: List ) + sealed class OperationalStateListAttributeSubscriptionState { + data class Success(val value: List) : + OperationalStateListAttributeSubscriptionState() + + data class Error(val exception: Exception) : OperationalStateListAttributeSubscriptionState() + + object SubscriptionEstablished : OperationalStateListAttributeSubscriptionState() + } + class OperationalErrorAttribute(val value: RvcOperationalStateClusterErrorStateStruct) + sealed class OperationalErrorAttributeSubscriptionState { + data class Success(val value: RvcOperationalStateClusterErrorStateStruct) : + OperationalErrorAttributeSubscriptionState() + + data class Error(val exception: Exception) : OperationalErrorAttributeSubscriptionState() + + object SubscriptionEstablished : OperationalErrorAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun pause(timedInvokeTimeout: Duration? = null): OperationalCommandResponse { val commandId: UInt = 0u @@ -272,6 +353,68 @@ class RvcOperationalStateCluster( return PhaseListAttribute(decodedValue) } + suspend fun subscribePhaseListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PhaseListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Phaselist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (!tlvReader.isNull()) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getString(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PhaseListAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PhaseListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPhaseAttribute(): CurrentPhaseAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -309,6 +452,62 @@ class RvcOperationalStateCluster( return CurrentPhaseAttribute(decodedValue) } + suspend fun subscribeCurrentPhaseAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentPhaseAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentphase attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentPhaseAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentPhaseAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCountdownTimeAttribute(): CountdownTimeAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -350,6 +549,66 @@ class RvcOperationalStateCluster( return CountdownTimeAttribute(decodedValue) } + suspend fun subscribeCountdownTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CountdownTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Countdowntime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CountdownTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CountdownTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalStateListAttribute(): OperationalStateListAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -388,6 +647,67 @@ class RvcOperationalStateCluster( return OperationalStateListAttribute(decodedValue) } + suspend fun subscribeOperationalStateListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OperationalStateListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalstatelist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + RvcOperationalStateClusterOperationalStateStruct.fromTlv(AnonymousTag, tlvReader) + ) + } + tlvReader.exitContainer() + } + + emit(OperationalStateListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(OperationalStateListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalStateAttribute(): UByte { val ATTRIBUTE_ID: UInt = 4u @@ -419,6 +739,58 @@ class RvcOperationalStateCluster( return decodedValue } + suspend fun subscribeOperationalStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalstate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalErrorAttribute(): OperationalErrorAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -451,6 +823,59 @@ class RvcOperationalStateCluster( return OperationalErrorAttribute(decodedValue) } + suspend fun subscribeOperationalErrorAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OperationalErrorAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalerror attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: RvcOperationalStateClusterErrorStateStruct = + RvcOperationalStateClusterErrorStateStruct.fromTlv(AnonymousTag, tlvReader) + + emit(OperationalErrorAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(OperationalErrorAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -489,6 +914,65 @@ class RvcOperationalStateCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -527,6 +1011,65 @@ class RvcOperationalStateCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -565,6 +1108,63 @@ class RvcOperationalStateCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -603,6 +1203,63 @@ class RvcOperationalStateCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -634,6 +1291,56 @@ class RvcOperationalStateCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -665,6 +1372,58 @@ class RvcOperationalStateCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(RvcOperationalStateCluster::class.java.name) const val CLUSTER_ID: UInt = 97u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcRunModeCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcRunModeCluster.kt index 46c2543f10edf9..2297e2fb439d4e 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcRunModeCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/RvcRunModeCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -41,16 +48,65 @@ class RvcRunModeCluster(private val controller: MatterController, private val en class SupportedModesAttribute(val value: List) + sealed class SupportedModesAttributeSubscriptionState { + data class Success(val value: List) : + SupportedModesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedModesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedModesAttributeSubscriptionState() + } + class OnModeAttribute(val value: UByte?) + sealed class OnModeAttributeSubscriptionState { + data class Success(val value: UByte?) : OnModeAttributeSubscriptionState() + + data class Error(val exception: Exception) : OnModeAttributeSubscriptionState() + + object SubscriptionEstablished : OnModeAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun changeToMode( newMode: UByte, timedInvokeTimeout: Duration? = null @@ -153,6 +209,65 @@ class RvcRunModeCluster(private val controller: MatterController, private val en return SupportedModesAttribute(decodedValue) } + suspend fun subscribeSupportedModesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedModesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedmodes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(RvcRunModeClusterModeOptionStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(SupportedModesAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedModesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -184,6 +299,56 @@ class RvcRunModeCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeCurrentModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOnModeAttribute(): OnModeAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -265,6 +430,66 @@ class RvcRunModeCluster(private val controller: MatterController, private val en } } + suspend fun subscribeOnModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OnModeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Onmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OnModeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OnModeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -303,6 +528,65 @@ class RvcRunModeCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -341,6 +625,65 @@ class RvcRunModeCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -379,6 +722,63 @@ class RvcRunModeCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -417,6 +817,63 @@ class RvcRunModeCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -448,6 +905,56 @@ class RvcRunModeCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -479,6 +986,58 @@ class RvcRunModeCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(RvcRunModeCluster::class.java.name) const val CLUSTER_ID: UInt = 84u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/SampleMeiCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/SampleMeiCluster.kt index 66f2110368163f..4514121f33fa31 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/SampleMeiCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/SampleMeiCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -41,12 +48,44 @@ class SampleMeiCluster(private val controller: MatterController, private val end class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun ping(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -187,6 +226,56 @@ class SampleMeiCluster(private val controller: MatterController, private val end } } + suspend fun subscribeFlipFlopAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Flipflop attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -225,6 +314,65 @@ class SampleMeiCluster(private val controller: MatterController, private val end return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -263,6 +411,65 @@ class SampleMeiCluster(private val controller: MatterController, private val end return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -301,6 +508,63 @@ class SampleMeiCluster(private val controller: MatterController, private val end return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -339,6 +603,63 @@ class SampleMeiCluster(private val controller: MatterController, private val end return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -370,6 +691,56 @@ class SampleMeiCluster(private val controller: MatterController, private val end return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -401,6 +772,58 @@ class SampleMeiCluster(private val controller: MatterController, private val end return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(SampleMeiCluster::class.java.name) const val CLUSTER_ID: UInt = 4294048800u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ScenesCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ScenesCluster.kt index f5087794fe5179..a1428d2a98780f 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ScenesCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ScenesCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -77,16 +85,65 @@ class ScenesCluster(private val controller: MatterController, private val endpoi class LastConfiguredByAttribute(val value: ULong?) + sealed class LastConfiguredByAttributeSubscriptionState { + data class Success(val value: ULong?) : LastConfiguredByAttributeSubscriptionState() + + data class Error(val exception: Exception) : LastConfiguredByAttributeSubscriptionState() + + object SubscriptionEstablished : LastConfiguredByAttributeSubscriptionState() + } + class FabricSceneInfoAttribute(val value: List) + sealed class FabricSceneInfoAttributeSubscriptionState { + data class Success(val value: List) : + FabricSceneInfoAttributeSubscriptionState() + + data class Error(val exception: Exception) : FabricSceneInfoAttributeSubscriptionState() + + object SubscriptionEstablished : FabricSceneInfoAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun addScene( groupID: UShort, sceneID: UByte, @@ -1006,6 +1063,61 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeSceneCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Scenecount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentSceneAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 1u @@ -1042,6 +1154,61 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeCurrentSceneAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentscene attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentGroupAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2u @@ -1078,6 +1245,61 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeCurrentGroupAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentgroup attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSceneValidAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 3u @@ -1114,6 +1336,61 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeSceneValidAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Scenevalid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNameSupportAttribute(): UByte { val ATTRIBUTE_ID: UInt = 4u @@ -1145,6 +1422,56 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeNameSupportAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Namesupport attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLastConfiguredByAttribute(): LastConfiguredByAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -1186,6 +1513,68 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return LastConfiguredByAttribute(decodedValue) } + suspend fun subscribeLastConfiguredByAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LastConfiguredByAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Lastconfiguredby attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LastConfiguredByAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LastConfiguredByAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSceneTableSizeAttribute(): UShort { val ATTRIBUTE_ID: UInt = 6u @@ -1217,6 +1606,58 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeSceneTableSizeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Scenetablesize attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFabricSceneInfoAttribute(): FabricSceneInfoAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -1255,6 +1696,65 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return FabricSceneInfoAttribute(decodedValue) } + suspend fun subscribeFabricSceneInfoAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FabricSceneInfoAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Fabricsceneinfo attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ScenesClusterSceneInfoStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(FabricSceneInfoAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(FabricSceneInfoAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1293,6 +1793,65 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1331,6 +1890,65 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1369,6 +1987,63 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1407,6 +2082,63 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1438,6 +2170,56 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1469,6 +2251,58 @@ class ScenesCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ScenesCluster::class.java.name) const val CLUSTER_ID: UInt = 5u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/SmokeCoAlarmCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/SmokeCoAlarmCluster.kt index 2b8b2e7944bf60..12a337827e4c2c 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/SmokeCoAlarmCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/SmokeCoAlarmCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -41,12 +49,44 @@ class SmokeCoAlarmCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun selfTestRequest(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -96,6 +136,58 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeExpressedStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Expressedstate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSmokeStateAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 1u @@ -132,6 +224,61 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeSmokeStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Smokestate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCOStateAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -168,6 +315,61 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeCOStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Costate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBatteryAlertAttribute(): UByte { val ATTRIBUTE_ID: UInt = 3u @@ -199,6 +401,56 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeBatteryAlertAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Batteryalert attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDeviceMutedAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 4u @@ -235,6 +487,61 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeDeviceMutedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Devicemuted attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTestInProgressAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 5u @@ -266,6 +573,58 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeTestInProgressAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Testinprogress attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readHardwareFaultAlertAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 6u @@ -297,6 +656,58 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeHardwareFaultAlertAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Hardwarefaultalert attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEndOfServiceAlertAttribute(): UByte { val ATTRIBUTE_ID: UInt = 7u @@ -328,6 +739,58 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeEndOfServiceAlertAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Endofservicealert attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInterconnectSmokeAlarmAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -364,6 +827,63 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeInterconnectSmokeAlarmAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Interconnectsmokealarm attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInterconnectCOAlarmAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -400,6 +920,63 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeInterconnectCOAlarmAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Interconnectcoalarm attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readContaminationStateAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -436,6 +1013,63 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeContaminationStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Contaminationstate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSmokeSensitivityLevelAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 11u @@ -515,6 +1149,63 @@ class SmokeCoAlarmCluster( } } + suspend fun subscribeSmokeSensitivityLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Smokesensitivitylevel attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readExpiryDateAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 12u @@ -551,6 +1242,61 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeExpiryDateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Expirydate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -589,6 +1335,65 @@ class SmokeCoAlarmCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -627,6 +1432,65 @@ class SmokeCoAlarmCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -665,6 +1529,63 @@ class SmokeCoAlarmCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -703,6 +1624,63 @@ class SmokeCoAlarmCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -734,6 +1712,56 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -765,6 +1793,58 @@ class SmokeCoAlarmCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(SmokeCoAlarmCluster::class.java.name) const val CLUSTER_ID: UInt = 92u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/SoftwareDiagnosticsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/SoftwareDiagnosticsCluster.kt index 196be440046c32..c3568e5825e8fe 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/SoftwareDiagnosticsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/SoftwareDiagnosticsCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.ULongSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -38,14 +45,55 @@ class SoftwareDiagnosticsCluster( ) { class ThreadMetricsAttribute(val value: List?) + sealed class ThreadMetricsAttributeSubscriptionState { + data class Success(val value: List?) : + ThreadMetricsAttributeSubscriptionState() + + data class Error(val exception: Exception) : ThreadMetricsAttributeSubscriptionState() + + object SubscriptionEstablished : ThreadMetricsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun resetWatermarks(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -106,6 +154,69 @@ class SoftwareDiagnosticsCluster( return ThreadMetricsAttribute(decodedValue) } + suspend fun subscribeThreadMetricsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ThreadMetricsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Threadmetrics attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + SoftwareDiagnosticsClusterThreadMetricsStruct.fromTlv(AnonymousTag, tlvReader) + ) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(ThreadMetricsAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ThreadMetricsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentHeapFreeAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 1u @@ -142,6 +253,63 @@ class SoftwareDiagnosticsCluster( return decodedValue } + suspend fun subscribeCurrentHeapFreeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentheapfree attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentHeapUsedAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 2u @@ -178,6 +346,63 @@ class SoftwareDiagnosticsCluster( return decodedValue } + suspend fun subscribeCurrentHeapUsedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentheapused attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentHeapHighWatermarkAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 3u @@ -214,6 +439,63 @@ class SoftwareDiagnosticsCluster( return decodedValue } + suspend fun subscribeCurrentHeapHighWatermarkAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentheaphighwatermark attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -252,6 +534,65 @@ class SoftwareDiagnosticsCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -290,6 +631,65 @@ class SoftwareDiagnosticsCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -328,6 +728,63 @@ class SoftwareDiagnosticsCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -366,6 +823,63 @@ class SoftwareDiagnosticsCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -397,6 +911,56 @@ class SoftwareDiagnosticsCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -428,6 +992,58 @@ class SoftwareDiagnosticsCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(SoftwareDiagnosticsCluster::class.java.name) const val CLUSTER_ID: UInt = 52u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/SwitchCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/SwitchCluster.kt index d3d4c67012010f..ec30f6aa7452e6 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/SwitchCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/SwitchCluster.kt @@ -17,11 +17,19 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -30,12 +38,44 @@ import matter.tlv.TlvReader class SwitchCluster(private val controller: MatterController, private val endpointId: UShort) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readNumberOfPositionsAttribute(): UByte { val ATTRIBUTE_ID: UInt = 0u @@ -67,6 +107,58 @@ class SwitchCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeNumberOfPositionsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofpositions attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPositionAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -98,6 +190,58 @@ class SwitchCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeCurrentPositionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentposition attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMultiPressMaxAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -134,6 +278,61 @@ class SwitchCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeMultiPressMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Multipressmax attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -172,6 +371,65 @@ class SwitchCluster(private val controller: MatterController, private val endpoi return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -210,6 +468,65 @@ class SwitchCluster(private val controller: MatterController, private val endpoi return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -248,6 +565,63 @@ class SwitchCluster(private val controller: MatterController, private val endpoi return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -286,6 +660,63 @@ class SwitchCluster(private val controller: MatterController, private val endpoi return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -317,6 +748,56 @@ class SwitchCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -348,6 +829,58 @@ class SwitchCluster(private val controller: MatterController, private val endpoi return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(SwitchCluster::class.java.name) const val CLUSTER_ID: UInt = 59u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/TargetNavigatorCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/TargetNavigatorCluster.kt index 8bcc7e0fa5c03e..aa48d2e32d4736 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/TargetNavigatorCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/TargetNavigatorCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,14 +48,55 @@ class TargetNavigatorCluster( class TargetListAttribute(val value: List) + sealed class TargetListAttributeSubscriptionState { + data class Success(val value: List) : + TargetListAttributeSubscriptionState() + + data class Error(val exception: Exception) : TargetListAttributeSubscriptionState() + + object SubscriptionEstablished : TargetListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun navigateTarget( target: UByte, data: String?, @@ -155,6 +203,63 @@ class TargetNavigatorCluster( return TargetListAttribute(decodedValue) } + suspend fun subscribeTargetListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TargetListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Targetlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(TargetNavigatorClusterTargetInfoStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(TargetListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(TargetListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentTargetAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 1u @@ -191,6 +296,61 @@ class TargetNavigatorCluster( return decodedValue } + suspend fun subscribeCurrentTargetAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currenttarget attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -229,6 +389,65 @@ class TargetNavigatorCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -267,6 +486,65 @@ class TargetNavigatorCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -305,6 +583,63 @@ class TargetNavigatorCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -343,6 +678,63 @@ class TargetNavigatorCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -374,6 +766,56 @@ class TargetNavigatorCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -405,6 +847,58 @@ class TargetNavigatorCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(TargetNavigatorCluster::class.java.name) const val CLUSTER_ID: UInt = 1285u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/TemperatureControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/TemperatureControlCluster.kt index 2bae8e12eae0b4..ef8fa756028407 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/TemperatureControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/TemperatureControlCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.ShortSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -39,14 +47,56 @@ class TemperatureControlCluster( ) { class SupportedTemperatureLevelsAttribute(val value: List?) + sealed class SupportedTemperatureLevelsAttributeSubscriptionState { + data class Success(val value: List?) : + SupportedTemperatureLevelsAttributeSubscriptionState() + + data class Error(val exception: Exception) : + SupportedTemperatureLevelsAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedTemperatureLevelsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun setTemperature( targetTemperature: Short?, targetTemperatureLevel: UByte?, @@ -115,6 +165,63 @@ class TemperatureControlCluster( return decodedValue } + suspend fun subscribeTemperatureSetpointAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Temperaturesetpoint attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinTemperatureAttribute(): Short? { val ATTRIBUTE_ID: UInt = 1u @@ -151,6 +258,63 @@ class TemperatureControlCluster( return decodedValue } + suspend fun subscribeMinTemperatureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Mintemperature attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxTemperatureAttribute(): Short? { val ATTRIBUTE_ID: UInt = 2u @@ -187,6 +351,63 @@ class TemperatureControlCluster( return decodedValue } + suspend fun subscribeMaxTemperatureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxtemperature attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStepAttribute(): Short? { val ATTRIBUTE_ID: UInt = 3u @@ -223,6 +444,61 @@ class TemperatureControlCluster( return decodedValue } + suspend fun subscribeStepAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Step attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSelectedTemperatureLevelAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 4u @@ -259,6 +535,63 @@ class TemperatureControlCluster( return decodedValue } + suspend fun subscribeSelectedTemperatureLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Selectedtemperaturelevel attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedTemperatureLevelsAttribute(): SupportedTemperatureLevelsAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -301,6 +634,71 @@ class TemperatureControlCluster( return SupportedTemperatureLevelsAttribute(decodedValue) } + suspend fun subscribeSupportedTemperatureLevelsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedTemperatureLevelsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedtemperaturelevels attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getString(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { + emit(SupportedTemperatureLevelsAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedTemperatureLevelsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -339,6 +737,65 @@ class TemperatureControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -377,6 +834,65 @@ class TemperatureControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -415,6 +931,63 @@ class TemperatureControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -453,6 +1026,63 @@ class TemperatureControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -484,6 +1114,56 @@ class TemperatureControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -515,6 +1195,58 @@ class TemperatureControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(TemperatureControlCluster::class.java.name) const val CLUSTER_ID: UInt = 86u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/TemperatureMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/TemperatureMeasurementCluster.kt index 4bf9afee80b853..5cd6ac3392242f 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/TemperatureMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/TemperatureMeasurementCluster.kt @@ -17,11 +17,18 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,18 +40,74 @@ class TemperatureMeasurementCluster( ) { class MeasuredValueAttribute(val value: Short?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Short?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Short?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Short?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Short?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Short?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -82,6 +145,62 @@ class TemperatureMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -119,6 +238,64 @@ class TemperatureMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -156,6 +333,64 @@ class TemperatureMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readToleranceAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 3u @@ -192,6 +427,61 @@ class TemperatureMeasurementCluster( return decodedValue } + suspend fun subscribeToleranceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Tolerance attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -230,6 +520,65 @@ class TemperatureMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -268,6 +617,65 @@ class TemperatureMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -306,6 +714,63 @@ class TemperatureMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -344,6 +809,63 @@ class TemperatureMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -375,6 +897,56 @@ class TemperatureMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -406,6 +978,58 @@ class TemperatureMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(TemperatureMeasurementCluster::class.java.name) const val CLUSTER_ID: UInt = 1026u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatCluster.kt index b29d3540e22082..274ed8e0234f00 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatCluster.kt @@ -20,11 +20,20 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.ByteSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.ShortSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -46,34 +55,156 @@ class ThermostatCluster(private val controller: MatterController, private val en class LocalTemperatureAttribute(val value: Short?) + sealed class LocalTemperatureAttributeSubscriptionState { + data class Success(val value: Short?) : LocalTemperatureAttributeSubscriptionState() + + data class Error(val exception: Exception) : LocalTemperatureAttributeSubscriptionState() + + object SubscriptionEstablished : LocalTemperatureAttributeSubscriptionState() + } + class OutdoorTemperatureAttribute(val value: Short?) + sealed class OutdoorTemperatureAttributeSubscriptionState { + data class Success(val value: Short?) : OutdoorTemperatureAttributeSubscriptionState() + + data class Error(val exception: Exception) : OutdoorTemperatureAttributeSubscriptionState() + + object SubscriptionEstablished : OutdoorTemperatureAttributeSubscriptionState() + } + class TemperatureSetpointHoldDurationAttribute(val value: UShort?) + sealed class TemperatureSetpointHoldDurationAttributeSubscriptionState { + data class Success(val value: UShort?) : + TemperatureSetpointHoldDurationAttributeSubscriptionState() + + data class Error(val exception: Exception) : + TemperatureSetpointHoldDurationAttributeSubscriptionState() + + object SubscriptionEstablished : TemperatureSetpointHoldDurationAttributeSubscriptionState() + } + class SetpointChangeAmountAttribute(val value: Short?) + sealed class SetpointChangeAmountAttributeSubscriptionState { + data class Success(val value: Short?) : SetpointChangeAmountAttributeSubscriptionState() + + data class Error(val exception: Exception) : SetpointChangeAmountAttributeSubscriptionState() + + object SubscriptionEstablished : SetpointChangeAmountAttributeSubscriptionState() + } + class OccupiedSetbackAttribute(val value: UByte?) + sealed class OccupiedSetbackAttributeSubscriptionState { + data class Success(val value: UByte?) : OccupiedSetbackAttributeSubscriptionState() + + data class Error(val exception: Exception) : OccupiedSetbackAttributeSubscriptionState() + + object SubscriptionEstablished : OccupiedSetbackAttributeSubscriptionState() + } + class OccupiedSetbackMinAttribute(val value: UByte?) + sealed class OccupiedSetbackMinAttributeSubscriptionState { + data class Success(val value: UByte?) : OccupiedSetbackMinAttributeSubscriptionState() + + data class Error(val exception: Exception) : OccupiedSetbackMinAttributeSubscriptionState() + + object SubscriptionEstablished : OccupiedSetbackMinAttributeSubscriptionState() + } + class OccupiedSetbackMaxAttribute(val value: UByte?) + sealed class OccupiedSetbackMaxAttributeSubscriptionState { + data class Success(val value: UByte?) : OccupiedSetbackMaxAttributeSubscriptionState() + + data class Error(val exception: Exception) : OccupiedSetbackMaxAttributeSubscriptionState() + + object SubscriptionEstablished : OccupiedSetbackMaxAttributeSubscriptionState() + } + class UnoccupiedSetbackAttribute(val value: UByte?) + sealed class UnoccupiedSetbackAttributeSubscriptionState { + data class Success(val value: UByte?) : UnoccupiedSetbackAttributeSubscriptionState() + + data class Error(val exception: Exception) : UnoccupiedSetbackAttributeSubscriptionState() + + object SubscriptionEstablished : UnoccupiedSetbackAttributeSubscriptionState() + } + class UnoccupiedSetbackMinAttribute(val value: UByte?) + sealed class UnoccupiedSetbackMinAttributeSubscriptionState { + data class Success(val value: UByte?) : UnoccupiedSetbackMinAttributeSubscriptionState() + + data class Error(val exception: Exception) : UnoccupiedSetbackMinAttributeSubscriptionState() + + object SubscriptionEstablished : UnoccupiedSetbackMinAttributeSubscriptionState() + } + class UnoccupiedSetbackMaxAttribute(val value: UByte?) + sealed class UnoccupiedSetbackMaxAttributeSubscriptionState { + data class Success(val value: UByte?) : UnoccupiedSetbackMaxAttributeSubscriptionState() + + data class Error(val exception: Exception) : UnoccupiedSetbackMaxAttributeSubscriptionState() + + object SubscriptionEstablished : UnoccupiedSetbackMaxAttributeSubscriptionState() + } + class ACCoilTemperatureAttribute(val value: Short?) + sealed class ACCoilTemperatureAttributeSubscriptionState { + data class Success(val value: Short?) : ACCoilTemperatureAttributeSubscriptionState() + + data class Error(val exception: Exception) : ACCoilTemperatureAttributeSubscriptionState() + + object SubscriptionEstablished : ACCoilTemperatureAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun setpointRaiseLower(mode: UByte, amount: Byte, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -292,6 +423,64 @@ class ThermostatCluster(private val controller: MatterController, private val en return LocalTemperatureAttribute(decodedValue) } + suspend fun subscribeLocalTemperatureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LocalTemperatureAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Localtemperature attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LocalTemperatureAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LocalTemperatureAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOutdoorTemperatureAttribute(): OutdoorTemperatureAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -333,6 +522,68 @@ class ThermostatCluster(private val controller: MatterController, private val en return OutdoorTemperatureAttribute(decodedValue) } + suspend fun subscribeOutdoorTemperatureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OutdoorTemperatureAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Outdoortemperature attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OutdoorTemperatureAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OutdoorTemperatureAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOccupancyAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -369,6 +620,61 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeOccupancyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Occupancy attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAbsMinHeatSetpointLimitAttribute(): Short? { val ATTRIBUTE_ID: UInt = 3u @@ -405,6 +711,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeAbsMinHeatSetpointLimitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Absminheatsetpointlimit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAbsMaxHeatSetpointLimitAttribute(): Short? { val ATTRIBUTE_ID: UInt = 4u @@ -441,6 +804,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeAbsMaxHeatSetpointLimitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Absmaxheatsetpointlimit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAbsMinCoolSetpointLimitAttribute(): Short? { val ATTRIBUTE_ID: UInt = 5u @@ -477,6 +897,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeAbsMinCoolSetpointLimitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Absmincoolsetpointlimit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAbsMaxCoolSetpointLimitAttribute(): Short? { val ATTRIBUTE_ID: UInt = 6u @@ -513,6 +990,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeAbsMaxCoolSetpointLimitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Absmaxcoolsetpointlimit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPICoolingDemandAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 7u @@ -549,6 +1083,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribePICoolingDemandAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Picoolingdemand attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPIHeatingDemandAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -585,6 +1176,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribePIHeatingDemandAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Piheatingdemand attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readHVACSystemTypeConfigurationAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -664,6 +1312,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeHVACSystemTypeConfigurationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Hvacsystemtypeconfiguration attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLocalTemperatureCalibrationAttribute(): Byte? { val ATTRIBUTE_ID: UInt = 16u @@ -743,6 +1448,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeLocalTemperatureCalibrationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Localtemperaturecalibration attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOccupiedCoolingSetpointAttribute(): Short? { val ATTRIBUTE_ID: UInt = 17u @@ -822,6 +1584,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeOccupiedCoolingSetpointAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Occupiedcoolingsetpoint attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOccupiedHeatingSetpointAttribute(): Short? { val ATTRIBUTE_ID: UInt = 18u @@ -901,6 +1720,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeOccupiedHeatingSetpointAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Occupiedheatingsetpoint attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUnoccupiedCoolingSetpointAttribute(): Short? { val ATTRIBUTE_ID: UInt = 19u @@ -980,6 +1856,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeUnoccupiedCoolingSetpointAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Unoccupiedcoolingsetpoint attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUnoccupiedHeatingSetpointAttribute(): Short? { val ATTRIBUTE_ID: UInt = 20u @@ -1059,6 +1992,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeUnoccupiedHeatingSetpointAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Unoccupiedheatingsetpoint attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinHeatSetpointLimitAttribute(): Short? { val ATTRIBUTE_ID: UInt = 21u @@ -1138,6 +2128,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeMinHeatSetpointLimitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 21u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minheatsetpointlimit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxHeatSetpointLimitAttribute(): Short? { val ATTRIBUTE_ID: UInt = 22u @@ -1217,6 +2264,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeMaxHeatSetpointLimitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 22u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxheatsetpointlimit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinCoolSetpointLimitAttribute(): Short? { val ATTRIBUTE_ID: UInt = 23u @@ -1296,6 +2400,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeMinCoolSetpointLimitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 23u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Mincoolsetpointlimit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxCoolSetpointLimitAttribute(): Short? { val ATTRIBUTE_ID: UInt = 24u @@ -1375,6 +2536,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeMaxCoolSetpointLimitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 24u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxcoolsetpointlimit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinSetpointDeadBandAttribute(): Byte? { val ATTRIBUTE_ID: UInt = 25u @@ -1451,6 +2669,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeMinSetpointDeadBandAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 25u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minsetpointdeadband attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRemoteSensingAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 26u @@ -1527,6 +2802,61 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeRemoteSensingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 26u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Remotesensing attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readControlSequenceOfOperationAttribute(): UByte { val ATTRIBUTE_ID: UInt = 27u @@ -1601,6 +2931,58 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeControlSequenceOfOperationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 27u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Controlsequenceofoperation attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSystemModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 28u @@ -1672,6 +3054,56 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeSystemModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 28u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Systemmode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readThermostatRunningModeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 30u @@ -1708,6 +3140,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeThermostatRunningModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 30u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Thermostatrunningmode attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartOfWeekAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 32u @@ -1740,8 +3229,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } else { null } - - return decodedValue + + return decodedValue + } + + suspend fun subscribeStartOfWeekAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 32u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Startofweek attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } } suspend fun readNumberOfWeeklyTransitionsAttribute(): UByte? { @@ -1780,6 +3324,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeNumberOfWeeklyTransitionsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 33u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofweeklytransitions attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfDailyTransitionsAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 34u @@ -1816,6 +3417,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeNumberOfDailyTransitionsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 34u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofdailytransitions attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTemperatureSetpointHoldAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 35u @@ -1895,6 +3553,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeTemperatureSetpointHoldAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 35u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Temperaturesetpointhold attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTemperatureSetpointHoldDurationAttribute(): TemperatureSetpointHoldDurationAttribute { val ATTRIBUTE_ID: UInt = 36u @@ -1982,6 +3697,70 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeTemperatureSetpointHoldDurationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 36u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TemperatureSetpointHoldDurationAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Temperaturesetpointholdduration attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(TemperatureSetpointHoldDurationAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(TemperatureSetpointHoldDurationAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readThermostatProgrammingOperationModeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 37u @@ -2063,6 +3842,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeThermostatProgrammingOperationModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 37u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Thermostatprogrammingoperationmode attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readThermostatRunningStateAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 41u @@ -2099,6 +3935,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeThermostatRunningStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 41u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Thermostatrunningstate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSetpointChangeSourceAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 48u @@ -2135,6 +4028,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeSetpointChangeSourceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 48u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Setpointchangesource attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSetpointChangeAmountAttribute(): SetpointChangeAmountAttribute { val ATTRIBUTE_ID: UInt = 49u @@ -2176,6 +4126,68 @@ class ThermostatCluster(private val controller: MatterController, private val en return SetpointChangeAmountAttribute(decodedValue) } + suspend fun subscribeSetpointChangeAmountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 49u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SetpointChangeAmountAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Setpointchangeamount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SetpointChangeAmountAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SetpointChangeAmountAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSetpointChangeSourceTimestampAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 50u @@ -2214,6 +4226,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeSetpointChangeSourceTimestampAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 50u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Setpointchangesourcetimestamp attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOccupiedSetbackAttribute(): OccupiedSetbackAttribute { val ATTRIBUTE_ID: UInt = 52u @@ -2295,6 +4364,68 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeOccupiedSetbackAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 52u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OccupiedSetbackAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Occupiedsetback attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OccupiedSetbackAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OccupiedSetbackAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOccupiedSetbackMinAttribute(): OccupiedSetbackMinAttribute { val ATTRIBUTE_ID: UInt = 53u @@ -2336,6 +4467,68 @@ class ThermostatCluster(private val controller: MatterController, private val en return OccupiedSetbackMinAttribute(decodedValue) } + suspend fun subscribeOccupiedSetbackMinAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 53u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OccupiedSetbackMinAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Occupiedsetbackmin attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OccupiedSetbackMinAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OccupiedSetbackMinAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOccupiedSetbackMaxAttribute(): OccupiedSetbackMaxAttribute { val ATTRIBUTE_ID: UInt = 54u @@ -2377,6 +4570,68 @@ class ThermostatCluster(private val controller: MatterController, private val en return OccupiedSetbackMaxAttribute(decodedValue) } + suspend fun subscribeOccupiedSetbackMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 54u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OccupiedSetbackMaxAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Occupiedsetbackmax attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OccupiedSetbackMaxAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OccupiedSetbackMaxAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUnoccupiedSetbackAttribute(): UnoccupiedSetbackAttribute { val ATTRIBUTE_ID: UInt = 55u @@ -2458,6 +4713,68 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeUnoccupiedSetbackAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 55u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UnoccupiedSetbackAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Unoccupiedsetback attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(UnoccupiedSetbackAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UnoccupiedSetbackAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUnoccupiedSetbackMinAttribute(): UnoccupiedSetbackMinAttribute { val ATTRIBUTE_ID: UInt = 56u @@ -2499,6 +4816,68 @@ class ThermostatCluster(private val controller: MatterController, private val en return UnoccupiedSetbackMinAttribute(decodedValue) } + suspend fun subscribeUnoccupiedSetbackMinAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 56u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UnoccupiedSetbackMinAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Unoccupiedsetbackmin attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(UnoccupiedSetbackMinAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UnoccupiedSetbackMinAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUnoccupiedSetbackMaxAttribute(): UnoccupiedSetbackMaxAttribute { val ATTRIBUTE_ID: UInt = 57u @@ -2532,12 +4911,74 @@ class ThermostatCluster(private val controller: MatterController, private val en } else { null } - } else { - tlvReader.getNull(AnonymousTag) - null - } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + return UnoccupiedSetbackMaxAttribute(decodedValue) + } + + suspend fun subscribeUnoccupiedSetbackMaxAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 57u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UnoccupiedSetbackMaxAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Unoccupiedsetbackmax attribute not found in Node State update" + } - return UnoccupiedSetbackMaxAttribute(decodedValue) + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(UnoccupiedSetbackMaxAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UnoccupiedSetbackMaxAttributeSubscriptionState.SubscriptionEstablished) + } + } + } } suspend fun readEmergencyHeatDeltaAttribute(): UByte? { @@ -2616,6 +5057,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeEmergencyHeatDeltaAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 58u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Emergencyheatdelta attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readACTypeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 64u @@ -2692,6 +5190,61 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeACTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 64u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Actype attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readACCapacityAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 65u @@ -2768,6 +5321,61 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeACCapacityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Accapacity attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readACRefrigerantTypeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 66u @@ -2844,6 +5452,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeACRefrigerantTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 66u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acrefrigeranttype attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readACCompressorTypeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 67u @@ -2920,6 +5585,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeACCompressorTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 67u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Accompressortype attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readACErrorCodeAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 68u @@ -2996,6 +5718,61 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeACErrorCodeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 68u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Acerrorcode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readACLouverPositionAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 69u @@ -3072,6 +5849,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeACLouverPositionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 69u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Aclouverposition attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readACCoilTemperatureAttribute(): ACCoilTemperatureAttribute { val ATTRIBUTE_ID: UInt = 70u @@ -3113,6 +5947,68 @@ class ThermostatCluster(private val controller: MatterController, private val en return ACCoilTemperatureAttribute(decodedValue) } + suspend fun subscribeACCoilTemperatureAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 70u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ACCoilTemperatureAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Accoiltemperature attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ACCoilTemperatureAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ACCoilTemperatureAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readACCapacityformatAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 71u @@ -3189,6 +6085,63 @@ class ThermostatCluster(private val controller: MatterController, private val en } } + suspend fun subscribeACCapacityformatAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 71u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Accapacityformat attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -3227,6 +6180,65 @@ class ThermostatCluster(private val controller: MatterController, private val en return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -3265,6 +6277,65 @@ class ThermostatCluster(private val controller: MatterController, private val en return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -3303,6 +6374,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -3341,6 +6469,63 @@ class ThermostatCluster(private val controller: MatterController, private val en return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -3372,6 +6557,56 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -3403,6 +6638,58 @@ class ThermostatCluster(private val controller: MatterController, private val en return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ThermostatCluster::class.java.name) const val CLUSTER_ID: UInt = 513u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatUserInterfaceConfigurationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatUserInterfaceConfigurationCluster.kt index 7f6112789198f1..1f5a0777fcb41f 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatUserInterfaceConfigurationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatUserInterfaceConfigurationCluster.kt @@ -20,9 +20,16 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,12 +45,44 @@ class ThermostatUserInterfaceConfigurationCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readTemperatureDisplayModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 0u @@ -118,6 +157,58 @@ class ThermostatUserInterfaceConfigurationCluster( } } + suspend fun subscribeTemperatureDisplayModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Temperaturedisplaymode attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readKeypadLockoutAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -189,6 +280,56 @@ class ThermostatUserInterfaceConfigurationCluster( } } + suspend fun subscribeKeypadLockoutAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Keypadlockout attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readScheduleProgrammingVisibilityAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -270,6 +411,63 @@ class ThermostatUserInterfaceConfigurationCluster( } } + suspend fun subscribeScheduleProgrammingVisibilityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Scheduleprogrammingvisibility attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -308,6 +506,65 @@ class ThermostatUserInterfaceConfigurationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -346,6 +603,65 @@ class ThermostatUserInterfaceConfigurationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -384,6 +700,63 @@ class ThermostatUserInterfaceConfigurationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -422,6 +795,63 @@ class ThermostatUserInterfaceConfigurationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -453,6 +883,56 @@ class ThermostatUserInterfaceConfigurationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -484,6 +964,58 @@ class ThermostatUserInterfaceConfigurationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ThermostatUserInterfaceConfigurationCluster::class.java.name) diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThreadNetworkDiagnosticsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThreadNetworkDiagnosticsCluster.kt index 33fa378831a73d..d4949cb4df2bf6 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThreadNetworkDiagnosticsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThreadNetworkDiagnosticsCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.ULongSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -38,54 +45,253 @@ class ThreadNetworkDiagnosticsCluster( ) { class ChannelAttribute(val value: UShort?) + sealed class ChannelAttributeSubscriptionState { + data class Success(val value: UShort?) : ChannelAttributeSubscriptionState() + + data class Error(val exception: Exception) : ChannelAttributeSubscriptionState() + + object SubscriptionEstablished : ChannelAttributeSubscriptionState() + } + class RoutingRoleAttribute(val value: UByte?) + sealed class RoutingRoleAttributeSubscriptionState { + data class Success(val value: UByte?) : RoutingRoleAttributeSubscriptionState() + + data class Error(val exception: Exception) : RoutingRoleAttributeSubscriptionState() + + object SubscriptionEstablished : RoutingRoleAttributeSubscriptionState() + } + class NetworkNameAttribute(val value: String?) + sealed class NetworkNameAttributeSubscriptionState { + data class Success(val value: String?) : NetworkNameAttributeSubscriptionState() + + data class Error(val exception: Exception) : NetworkNameAttributeSubscriptionState() + + object SubscriptionEstablished : NetworkNameAttributeSubscriptionState() + } + class PanIdAttribute(val value: UShort?) + sealed class PanIdAttributeSubscriptionState { + data class Success(val value: UShort?) : PanIdAttributeSubscriptionState() + + data class Error(val exception: Exception) : PanIdAttributeSubscriptionState() + + object SubscriptionEstablished : PanIdAttributeSubscriptionState() + } + class ExtendedPanIdAttribute(val value: ULong?) + sealed class ExtendedPanIdAttributeSubscriptionState { + data class Success(val value: ULong?) : ExtendedPanIdAttributeSubscriptionState() + + data class Error(val exception: Exception) : ExtendedPanIdAttributeSubscriptionState() + + object SubscriptionEstablished : ExtendedPanIdAttributeSubscriptionState() + } + class MeshLocalPrefixAttribute(val value: ByteArray?) + sealed class MeshLocalPrefixAttributeSubscriptionState { + data class Success(val value: ByteArray?) : MeshLocalPrefixAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeshLocalPrefixAttributeSubscriptionState() + + object SubscriptionEstablished : MeshLocalPrefixAttributeSubscriptionState() + } + class NeighborTableAttribute(val value: List) + sealed class NeighborTableAttributeSubscriptionState { + data class Success(val value: List) : + NeighborTableAttributeSubscriptionState() + + data class Error(val exception: Exception) : NeighborTableAttributeSubscriptionState() + + object SubscriptionEstablished : NeighborTableAttributeSubscriptionState() + } + class RouteTableAttribute(val value: List) + sealed class RouteTableAttributeSubscriptionState { + data class Success(val value: List) : + RouteTableAttributeSubscriptionState() + + data class Error(val exception: Exception) : RouteTableAttributeSubscriptionState() + + object SubscriptionEstablished : RouteTableAttributeSubscriptionState() + } + class PartitionIdAttribute(val value: UInt?) + sealed class PartitionIdAttributeSubscriptionState { + data class Success(val value: UInt?) : PartitionIdAttributeSubscriptionState() + + data class Error(val exception: Exception) : PartitionIdAttributeSubscriptionState() + + object SubscriptionEstablished : PartitionIdAttributeSubscriptionState() + } + class WeightingAttribute(val value: UShort?) + sealed class WeightingAttributeSubscriptionState { + data class Success(val value: UShort?) : WeightingAttributeSubscriptionState() + + data class Error(val exception: Exception) : WeightingAttributeSubscriptionState() + + object SubscriptionEstablished : WeightingAttributeSubscriptionState() + } + class DataVersionAttribute(val value: UShort?) + sealed class DataVersionAttributeSubscriptionState { + data class Success(val value: UShort?) : DataVersionAttributeSubscriptionState() + + data class Error(val exception: Exception) : DataVersionAttributeSubscriptionState() + + object SubscriptionEstablished : DataVersionAttributeSubscriptionState() + } + class StableDataVersionAttribute(val value: UShort?) + sealed class StableDataVersionAttributeSubscriptionState { + data class Success(val value: UShort?) : StableDataVersionAttributeSubscriptionState() + + data class Error(val exception: Exception) : StableDataVersionAttributeSubscriptionState() + + object SubscriptionEstablished : StableDataVersionAttributeSubscriptionState() + } + class LeaderRouterIdAttribute(val value: UByte?) + sealed class LeaderRouterIdAttributeSubscriptionState { + data class Success(val value: UByte?) : LeaderRouterIdAttributeSubscriptionState() + + data class Error(val exception: Exception) : LeaderRouterIdAttributeSubscriptionState() + + object SubscriptionEstablished : LeaderRouterIdAttributeSubscriptionState() + } + class ActiveTimestampAttribute(val value: ULong?) + sealed class ActiveTimestampAttributeSubscriptionState { + data class Success(val value: ULong?) : ActiveTimestampAttributeSubscriptionState() + + data class Error(val exception: Exception) : ActiveTimestampAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveTimestampAttributeSubscriptionState() + } + class PendingTimestampAttribute(val value: ULong?) + sealed class PendingTimestampAttributeSubscriptionState { + data class Success(val value: ULong?) : PendingTimestampAttributeSubscriptionState() + + data class Error(val exception: Exception) : PendingTimestampAttributeSubscriptionState() + + object SubscriptionEstablished : PendingTimestampAttributeSubscriptionState() + } + class DelayAttribute(val value: UInt?) + sealed class DelayAttributeSubscriptionState { + data class Success(val value: UInt?) : DelayAttributeSubscriptionState() + + data class Error(val exception: Exception) : DelayAttributeSubscriptionState() + + object SubscriptionEstablished : DelayAttributeSubscriptionState() + } + class SecurityPolicyAttribute(val value: ThreadNetworkDiagnosticsClusterSecurityPolicy?) + sealed class SecurityPolicyAttributeSubscriptionState { + data class Success(val value: ThreadNetworkDiagnosticsClusterSecurityPolicy?) : + SecurityPolicyAttributeSubscriptionState() + + data class Error(val exception: Exception) : SecurityPolicyAttributeSubscriptionState() + + object SubscriptionEstablished : SecurityPolicyAttributeSubscriptionState() + } + class ChannelPage0MaskAttribute(val value: ByteArray?) + sealed class ChannelPage0MaskAttributeSubscriptionState { + data class Success(val value: ByteArray?) : ChannelPage0MaskAttributeSubscriptionState() + + data class Error(val exception: Exception) : ChannelPage0MaskAttributeSubscriptionState() + + object SubscriptionEstablished : ChannelPage0MaskAttributeSubscriptionState() + } + class OperationalDatasetComponentsAttribute( val value: ThreadNetworkDiagnosticsClusterOperationalDatasetComponents? ) + sealed class OperationalDatasetComponentsAttributeSubscriptionState { + data class Success(val value: ThreadNetworkDiagnosticsClusterOperationalDatasetComponents?) : + OperationalDatasetComponentsAttributeSubscriptionState() + + data class Error(val exception: Exception) : + OperationalDatasetComponentsAttributeSubscriptionState() + + object SubscriptionEstablished : OperationalDatasetComponentsAttributeSubscriptionState() + } + class ActiveNetworkFaultsListAttribute(val value: List) + sealed class ActiveNetworkFaultsListAttributeSubscriptionState { + data class Success(val value: List) : + ActiveNetworkFaultsListAttributeSubscriptionState() + + data class Error(val exception: Exception) : + ActiveNetworkFaultsListAttributeSubscriptionState() + + object SubscriptionEstablished : ActiveNetworkFaultsListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun resetCounts(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -141,6 +347,62 @@ class ThreadNetworkDiagnosticsCluster( return ChannelAttribute(decodedValue) } + suspend fun subscribeChannelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ChannelAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Channel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ChannelAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ChannelAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRoutingRoleAttribute(): RoutingRoleAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -178,6 +440,62 @@ class ThreadNetworkDiagnosticsCluster( return RoutingRoleAttribute(decodedValue) } + suspend fun subscribeRoutingRoleAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + RoutingRoleAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Routingrole attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(RoutingRoleAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(RoutingRoleAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNetworkNameAttribute(): NetworkNameAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -215,6 +533,62 @@ class ThreadNetworkDiagnosticsCluster( return NetworkNameAttribute(decodedValue) } + suspend fun subscribeNetworkNameAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NetworkNameAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Networkname attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (!tlvReader.isNull()) { + tlvReader.getString(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NetworkNameAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NetworkNameAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPanIdAttribute(): PanIdAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -252,6 +626,62 @@ class ThreadNetworkDiagnosticsCluster( return PanIdAttribute(decodedValue) } + suspend fun subscribePanIdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PanIdAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Panid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PanIdAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PanIdAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readExtendedPanIdAttribute(): ExtendedPanIdAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -289,6 +719,62 @@ class ThreadNetworkDiagnosticsCluster( return ExtendedPanIdAttribute(decodedValue) } + suspend fun subscribeExtendedPanIdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ExtendedPanIdAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Extendedpanid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + tlvReader.getULong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ExtendedPanIdAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ExtendedPanIdAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeshLocalPrefixAttribute(): MeshLocalPrefixAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -326,6 +812,64 @@ class ThreadNetworkDiagnosticsCluster( return MeshLocalPrefixAttribute(decodedValue) } + suspend fun subscribeMeshLocalPrefixAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeshLocalPrefixAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Meshlocalprefix attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray? = + if (!tlvReader.isNull()) { + tlvReader.getByteArray(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeshLocalPrefixAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeshLocalPrefixAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOverrunCountAttribute(): ULong? { val ATTRIBUTE_ID: UInt = 6u @@ -362,6 +906,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeOverrunCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Overruncount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ULongSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNeighborTableAttribute(): NeighborTableAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -400,6 +999,68 @@ class ThreadNetworkDiagnosticsCluster( return NeighborTableAttribute(decodedValue) } + suspend fun subscribeNeighborTableAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NeighborTableAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Neighbortable attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + ThreadNetworkDiagnosticsClusterNeighborTableStruct.fromTlv( + AnonymousTag, + tlvReader + ) + ) + } + tlvReader.exitContainer() + } + + emit(NeighborTableAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(NeighborTableAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRouteTableAttribute(): RouteTableAttribute { val ATTRIBUTE_ID: UInt = 8u @@ -438,6 +1099,65 @@ class ThreadNetworkDiagnosticsCluster( return RouteTableAttribute(decodedValue) } + suspend fun subscribeRouteTableAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + RouteTableAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Routetable attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add( + ThreadNetworkDiagnosticsClusterRouteTableStruct.fromTlv(AnonymousTag, tlvReader) + ) + } + tlvReader.exitContainer() + } + + emit(RouteTableAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(RouteTableAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPartitionIdAttribute(): PartitionIdAttribute { val ATTRIBUTE_ID: UInt = 9u @@ -475,6 +1195,62 @@ class ThreadNetworkDiagnosticsCluster( return PartitionIdAttribute(decodedValue) } + suspend fun subscribePartitionIdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PartitionIdAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Partitionid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + tlvReader.getUInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PartitionIdAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PartitionIdAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWeightingAttribute(): WeightingAttribute { val ATTRIBUTE_ID: UInt = 10u @@ -512,6 +1288,62 @@ class ThreadNetworkDiagnosticsCluster( return WeightingAttribute(decodedValue) } + suspend fun subscribeWeightingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + WeightingAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Weighting attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(WeightingAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(WeightingAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDataVersionAttribute(): DataVersionAttribute { val ATTRIBUTE_ID: UInt = 11u @@ -549,6 +1381,62 @@ class ThreadNetworkDiagnosticsCluster( return DataVersionAttribute(decodedValue) } + suspend fun subscribeDataVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DataVersionAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dataversion attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(DataVersionAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(DataVersionAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStableDataVersionAttribute(): StableDataVersionAttribute { val ATTRIBUTE_ID: UInt = 12u @@ -586,6 +1474,64 @@ class ThreadNetworkDiagnosticsCluster( return StableDataVersionAttribute(decodedValue) } + suspend fun subscribeStableDataVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StableDataVersionAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Stabledataversion attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(StableDataVersionAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StableDataVersionAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLeaderRouterIdAttribute(): LeaderRouterIdAttribute { val ATTRIBUTE_ID: UInt = 13u @@ -623,6 +1569,64 @@ class ThreadNetworkDiagnosticsCluster( return LeaderRouterIdAttribute(decodedValue) } + suspend fun subscribeLeaderRouterIdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 13u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LeaderRouterIdAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Leaderrouterid attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LeaderRouterIdAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LeaderRouterIdAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDetachedRoleCountAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 14u @@ -659,6 +1663,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeDetachedRoleCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 14u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Detachedrolecount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readChildRoleCountAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 15u @@ -695,6 +1756,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeChildRoleCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 15u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Childrolecount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRouterRoleCountAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16u @@ -731,6 +1849,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRouterRoleCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Routerrolecount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLeaderRoleCountAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 17u @@ -767,6 +1942,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeLeaderRoleCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Leaderrolecount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttachAttemptCountAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 18u @@ -803,6 +2035,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeAttachAttemptCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Attachattemptcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPartitionIdChangeCountAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 19u @@ -839,6 +2128,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribePartitionIdChangeCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Partitionidchangecount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBetterPartitionAttachAttemptCountAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 20u @@ -877,6 +2223,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeBetterPartitionAttachAttemptCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Betterpartitionattachattemptcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readParentChangeCountAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 21u @@ -913,6 +2316,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeParentChangeCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 21u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Parentchangecount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxTotalCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 22u @@ -949,6 +2409,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxTotalCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 22u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Txtotalcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxUnicastCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 23u @@ -985,6 +2500,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxUnicastCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 23u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txunicastcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxBroadcastCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 24u @@ -1021,6 +2593,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxBroadcastCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 24u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txbroadcastcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxAckRequestedCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 25u @@ -1057,6 +2686,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxAckRequestedCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 25u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txackrequestedcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxAckedCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 26u @@ -1093,6 +2779,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxAckedCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 26u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Txackedcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxNoAckRequestedCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 27u @@ -1129,6 +2870,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxNoAckRequestedCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 27u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txnoackrequestedcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxDataCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 28u @@ -1165,6 +2963,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxDataCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 28u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Txdatacount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxDataPollCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 29u @@ -1201,6 +3054,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxDataPollCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 29u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txdatapollcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxBeaconCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 30u @@ -1237,6 +3147,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxBeaconCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 30u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Txbeaconcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxBeaconRequestCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 31u @@ -1273,6 +3238,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxBeaconRequestCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 31u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txbeaconrequestcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxOtherCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 32u @@ -1309,6 +3331,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxOtherCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 32u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Txothercount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxRetryCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 33u @@ -1345,6 +3422,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxRetryCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 33u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Txretrycount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxDirectMaxRetryExpiryCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 34u @@ -1381,6 +3513,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxDirectMaxRetryExpiryCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 34u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txdirectmaxretryexpirycount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxIndirectMaxRetryExpiryCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 35u @@ -1419,6 +3608,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxIndirectMaxRetryExpiryCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 35u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txindirectmaxretryexpirycount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxErrCcaCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 36u @@ -1455,6 +3701,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxErrCcaCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 36u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Txerrccacount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxErrAbortCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 37u @@ -1491,6 +3792,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxErrAbortCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 37u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txerrabortcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTxErrBusyChannelCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 38u @@ -1527,6 +3885,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeTxErrBusyChannelCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 38u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Txerrbusychannelcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxTotalCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 39u @@ -1563,6 +3978,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxTotalCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 39u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rxtotalcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxUnicastCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 40u @@ -1599,6 +4069,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxUnicastCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 40u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxunicastcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxBroadcastCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 41u @@ -1635,6 +4162,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxBroadcastCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 41u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxbroadcastcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxDataCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 42u @@ -1671,6 +4255,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxDataCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 42u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rxdatacount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxDataPollCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 43u @@ -1707,6 +4346,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxDataPollCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 43u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxdatapollcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxBeaconCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 44u @@ -1743,6 +4439,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxBeaconCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 44u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rxbeaconcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxBeaconRequestCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 45u @@ -1779,6 +4530,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxBeaconRequestCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 45u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxbeaconrequestcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxOtherCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 46u @@ -1815,6 +4623,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxOtherCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 46u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rxothercount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxAddressFilteredCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 47u @@ -1851,6 +4714,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxAddressFilteredCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 47u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxaddressfilteredcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxDestAddrFilteredCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 48u @@ -1884,7 +4804,64 @@ class ThreadNetworkDiagnosticsCluster( null } - return decodedValue + return decodedValue + } + + suspend fun subscribeRxDestAddrFilteredCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 48u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxdestaddrfilteredcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } } suspend fun readRxDuplicatedCountAttribute(): UInt? { @@ -1923,6 +4900,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxDuplicatedCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 49u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxduplicatedcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxErrNoFrameCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 50u @@ -1959,6 +4993,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxErrNoFrameCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 50u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxerrnoframecount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxErrUnknownNeighborCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 51u @@ -1995,6 +5086,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxErrUnknownNeighborCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 51u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxerrunknownneighborcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxErrInvalidSrcAddrCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 52u @@ -2031,6 +5179,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxErrInvalidSrcAddrCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 52u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxerrinvalidsrcaddrcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxErrSecCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 53u @@ -2067,6 +5272,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxErrSecCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 53u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rxerrseccount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxErrFcsCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 54u @@ -2103,6 +5363,61 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxErrFcsCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 54u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rxerrfcscount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRxErrOtherCountAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 55u @@ -2139,6 +5454,63 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeRxErrOtherCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 55u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rxerrothercount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveTimestampAttribute(): ActiveTimestampAttribute { val ATTRIBUTE_ID: UInt = 56u @@ -2180,6 +5552,68 @@ class ThreadNetworkDiagnosticsCluster( return ActiveTimestampAttribute(decodedValue) } + suspend fun subscribeActiveTimestampAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 56u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveTimestampAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activetimestamp attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ActiveTimestampAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveTimestampAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPendingTimestampAttribute(): PendingTimestampAttribute { val ATTRIBUTE_ID: UInt = 57u @@ -2221,6 +5655,68 @@ class ThreadNetworkDiagnosticsCluster( return PendingTimestampAttribute(decodedValue) } + suspend fun subscribePendingTimestampAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 57u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PendingTimestampAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Pendingtimestamp attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PendingTimestampAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PendingTimestampAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDelayAttribute(): DelayAttribute { val ATTRIBUTE_ID: UInt = 58u @@ -2262,6 +5758,66 @@ class ThreadNetworkDiagnosticsCluster( return DelayAttribute(decodedValue) } + suspend fun subscribeDelayAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 58u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DelayAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Delay attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(DelayAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(DelayAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSecurityPolicyAttribute(): SecurityPolicyAttribute { val ATTRIBUTE_ID: UInt = 59u @@ -2299,6 +5855,64 @@ class ThreadNetworkDiagnosticsCluster( return SecurityPolicyAttribute(decodedValue) } + suspend fun subscribeSecurityPolicyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 59u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SecurityPolicyAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Securitypolicy attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ThreadNetworkDiagnosticsClusterSecurityPolicy? = + if (!tlvReader.isNull()) { + ThreadNetworkDiagnosticsClusterSecurityPolicy.fromTlv(AnonymousTag, tlvReader) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SecurityPolicyAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SecurityPolicyAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readChannelPage0MaskAttribute(): ChannelPage0MaskAttribute { val ATTRIBUTE_ID: UInt = 60u @@ -2336,6 +5950,64 @@ class ThreadNetworkDiagnosticsCluster( return ChannelPage0MaskAttribute(decodedValue) } + suspend fun subscribeChannelPage0MaskAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 60u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ChannelPage0MaskAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Channelpage0mask attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray? = + if (!tlvReader.isNull()) { + tlvReader.getByteArray(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ChannelPage0MaskAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ChannelPage0MaskAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalDatasetComponentsAttribute(): OperationalDatasetComponentsAttribute { val ATTRIBUTE_ID: UInt = 61u @@ -2373,6 +6045,69 @@ class ThreadNetworkDiagnosticsCluster( return OperationalDatasetComponentsAttribute(decodedValue) } + suspend fun subscribeOperationalDatasetComponentsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 61u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OperationalDatasetComponentsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationaldatasetcomponents attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ThreadNetworkDiagnosticsClusterOperationalDatasetComponents? = + if (!tlvReader.isNull()) { + ThreadNetworkDiagnosticsClusterOperationalDatasetComponents.fromTlv( + AnonymousTag, + tlvReader + ) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(OperationalDatasetComponentsAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OperationalDatasetComponentsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveNetworkFaultsListAttribute(): ActiveNetworkFaultsListAttribute { val ATTRIBUTE_ID: UInt = 62u @@ -2411,6 +6146,65 @@ class ThreadNetworkDiagnosticsCluster( return ActiveNetworkFaultsListAttribute(decodedValue) } + suspend fun subscribeActiveNetworkFaultsListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 62u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ActiveNetworkFaultsListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activenetworkfaultslist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(ActiveNetworkFaultsListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ActiveNetworkFaultsListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -2449,6 +6243,65 @@ class ThreadNetworkDiagnosticsCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -2487,6 +6340,65 @@ class ThreadNetworkDiagnosticsCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -2525,6 +6437,63 @@ class ThreadNetworkDiagnosticsCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -2563,6 +6532,63 @@ class ThreadNetworkDiagnosticsCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -2594,6 +6620,56 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -2625,6 +6701,58 @@ class ThreadNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ThreadNetworkDiagnosticsCluster::class.java.name) const val CLUSTER_ID: UInt = 53u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/TimeFormatLocalizationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/TimeFormatLocalizationCluster.kt index 41dc7099e7268b..c16c37cdb0d766 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/TimeFormatLocalizationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/TimeFormatLocalizationCluster.kt @@ -20,9 +20,16 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,14 +45,55 @@ class TimeFormatLocalizationCluster( ) { class SupportedCalendarTypesAttribute(val value: List?) + sealed class SupportedCalendarTypesAttributeSubscriptionState { + data class Success(val value: List?) : + SupportedCalendarTypesAttributeSubscriptionState() + + data class Error(val exception: Exception) : SupportedCalendarTypesAttributeSubscriptionState() + + object SubscriptionEstablished : SupportedCalendarTypesAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readHourFormatAttribute(): UByte { val ATTRIBUTE_ID: UInt = 0u @@ -117,6 +165,56 @@ class TimeFormatLocalizationCluster( } } + suspend fun subscribeHourFormatAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Hourformat attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readActiveCalendarTypeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 1u @@ -193,6 +291,63 @@ class TimeFormatLocalizationCluster( } } + suspend fun subscribeActiveCalendarTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Activecalendartype attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportedCalendarTypesAttribute(): SupportedCalendarTypesAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -235,6 +390,69 @@ class TimeFormatLocalizationCluster( return SupportedCalendarTypesAttribute(decodedValue) } + suspend fun subscribeSupportedCalendarTypesAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SupportedCalendarTypesAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportedcalendartypes attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(SupportedCalendarTypesAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SupportedCalendarTypesAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -273,6 +491,65 @@ class TimeFormatLocalizationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -311,6 +588,65 @@ class TimeFormatLocalizationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -349,6 +685,63 @@ class TimeFormatLocalizationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -387,6 +780,63 @@ class TimeFormatLocalizationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -418,6 +868,56 @@ class TimeFormatLocalizationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -449,6 +949,58 @@ class TimeFormatLocalizationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(TimeFormatLocalizationCluster::class.java.name) const val CLUSTER_ID: UInt = 44u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/TimeSynchronizationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/TimeSynchronizationCluster.kt index 5989f79f117659..13edfff80a046d 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/TimeSynchronizationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/TimeSynchronizationCluster.kt @@ -20,11 +20,19 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -41,24 +49,107 @@ class TimeSynchronizationCluster( class UTCTimeAttribute(val value: ULong?) + sealed class UTCTimeAttributeSubscriptionState { + data class Success(val value: ULong?) : UTCTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : UTCTimeAttributeSubscriptionState() + + object SubscriptionEstablished : UTCTimeAttributeSubscriptionState() + } + class TrustedTimeSourceAttribute(val value: TimeSynchronizationClusterTrustedTimeSourceStruct?) + sealed class TrustedTimeSourceAttributeSubscriptionState { + data class Success(val value: TimeSynchronizationClusterTrustedTimeSourceStruct?) : + TrustedTimeSourceAttributeSubscriptionState() + + data class Error(val exception: Exception) : TrustedTimeSourceAttributeSubscriptionState() + + object SubscriptionEstablished : TrustedTimeSourceAttributeSubscriptionState() + } + class DefaultNTPAttribute(val value: String?) + sealed class DefaultNTPAttributeSubscriptionState { + data class Success(val value: String?) : DefaultNTPAttributeSubscriptionState() + + data class Error(val exception: Exception) : DefaultNTPAttributeSubscriptionState() + + object SubscriptionEstablished : DefaultNTPAttributeSubscriptionState() + } + class TimeZoneAttribute(val value: List?) + sealed class TimeZoneAttributeSubscriptionState { + data class Success(val value: List?) : + TimeZoneAttributeSubscriptionState() + + data class Error(val exception: Exception) : TimeZoneAttributeSubscriptionState() + + object SubscriptionEstablished : TimeZoneAttributeSubscriptionState() + } + class DSTOffsetAttribute(val value: List?) + sealed class DSTOffsetAttributeSubscriptionState { + data class Success(val value: List?) : + DSTOffsetAttributeSubscriptionState() + + data class Error(val exception: Exception) : DSTOffsetAttributeSubscriptionState() + + object SubscriptionEstablished : DSTOffsetAttributeSubscriptionState() + } + class LocalTimeAttribute(val value: ULong?) + sealed class LocalTimeAttributeSubscriptionState { + data class Success(val value: ULong?) : LocalTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : LocalTimeAttributeSubscriptionState() + + object SubscriptionEstablished : LocalTimeAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun setUTCTime( UTCTime: ULong, granularity: UByte, @@ -254,6 +345,62 @@ class TimeSynchronizationCluster( return UTCTimeAttribute(decodedValue) } + suspend fun subscribeUTCTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UTCTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Utctime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + tlvReader.getULong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(UTCTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UTCTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGranularityAttribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -285,6 +432,56 @@ class TimeSynchronizationCluster( return decodedValue } + suspend fun subscribeGranularityAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Granularity attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTimeSourceAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u @@ -321,6 +518,61 @@ class TimeSynchronizationCluster( return decodedValue } + suspend fun subscribeTimeSourceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Timesource attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTrustedTimeSourceAttribute(): TrustedTimeSourceAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -362,6 +614,68 @@ class TimeSynchronizationCluster( return TrustedTimeSourceAttribute(decodedValue) } + suspend fun subscribeTrustedTimeSourceAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TrustedTimeSourceAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Trustedtimesource attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: TimeSynchronizationClusterTrustedTimeSourceStruct? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + TimeSynchronizationClusterTrustedTimeSourceStruct.fromTlv(AnonymousTag, tlvReader) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(TrustedTimeSourceAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(TrustedTimeSourceAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDefaultNTPAttribute(): DefaultNTPAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -403,6 +717,66 @@ class TimeSynchronizationCluster( return DefaultNTPAttribute(decodedValue) } + suspend fun subscribeDefaultNTPAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DefaultNTPAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Defaultntp attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(DefaultNTPAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(DefaultNTPAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTimeZoneAttribute(): TimeZoneAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -445,6 +819,67 @@ class TimeSynchronizationCluster( return TimeZoneAttribute(decodedValue) } + suspend fun subscribeTimeZoneAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TimeZoneAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Timezone attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(TimeSynchronizationClusterTimeZoneStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(TimeZoneAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(TimeZoneAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDSTOffsetAttribute(): DSTOffsetAttribute { val ATTRIBUTE_ID: UInt = 6u @@ -487,6 +922,67 @@ class TimeSynchronizationCluster( return DSTOffsetAttribute(decodedValue) } + suspend fun subscribeDSTOffsetAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DSTOffsetAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Dstoffset attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List? = + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(TimeSynchronizationClusterDSTOffsetStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + } else { + null + } + + decodedValue?.let { emit(DSTOffsetAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(DSTOffsetAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLocalTimeAttribute(): LocalTimeAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -528,6 +1024,66 @@ class TimeSynchronizationCluster( return LocalTimeAttribute(decodedValue) } + suspend fun subscribeLocalTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LocalTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Localtime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(LocalTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(LocalTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTimeZoneDatabaseAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -564,6 +1120,63 @@ class TimeSynchronizationCluster( return decodedValue } + suspend fun subscribeTimeZoneDatabaseAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Timezonedatabase attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNTPServerAvailableAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 9u @@ -600,6 +1213,63 @@ class TimeSynchronizationCluster( return decodedValue } + suspend fun subscribeNTPServerAvailableAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Ntpserveravailable attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTimeZoneListMaxSizeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -636,6 +1306,63 @@ class TimeSynchronizationCluster( return decodedValue } + suspend fun subscribeTimeZoneListMaxSizeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Timezonelistmaxsize attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readDSTOffsetListMaxSizeAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 11u @@ -672,6 +1399,63 @@ class TimeSynchronizationCluster( return decodedValue } + suspend fun subscribeDSTOffsetListMaxSizeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Dstoffsetlistmaxsize attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSupportsDNSResolveAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 12u @@ -708,6 +1492,63 @@ class TimeSynchronizationCluster( return decodedValue } + suspend fun subscribeSupportsDNSResolveAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Supportsdnsresolve attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -746,6 +1587,65 @@ class TimeSynchronizationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -784,6 +1684,65 @@ class TimeSynchronizationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -822,6 +1781,63 @@ class TimeSynchronizationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -860,6 +1876,63 @@ class TimeSynchronizationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -891,6 +1964,56 @@ class TimeSynchronizationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -922,6 +2045,58 @@ class TimeSynchronizationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(TimeSynchronizationCluster::class.java.name) const val CLUSTER_ID: UInt = 56u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/TimerCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/TimerCluster.kt index cbba2941c53728..c019d26a8a29bf 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/TimerCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/TimerCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -36,12 +43,44 @@ import matter.tlv.TlvWriter class TimerCluster(private val controller: MatterController, private val endpointId: UShort) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun setTimer(newTime: UInt, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -154,6 +193,56 @@ class TimerCluster(private val controller: MatterController, private val endpoin return decodedValue } + suspend fun subscribeSetTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Settime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTimeRemainingAttribute(): UInt { val ATTRIBUTE_ID: UInt = 1u @@ -185,6 +274,56 @@ class TimerCluster(private val controller: MatterController, private val endpoin return decodedValue } + suspend fun subscribeTimeRemainingAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Timeremaining attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTimerStateAttribute(): UByte { val ATTRIBUTE_ID: UInt = 2u @@ -216,6 +355,56 @@ class TimerCluster(private val controller: MatterController, private val endpoin return decodedValue } + suspend fun subscribeTimerStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Timerstate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -254,6 +443,65 @@ class TimerCluster(private val controller: MatterController, private val endpoin return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -292,6 +540,65 @@ class TimerCluster(private val controller: MatterController, private val endpoin return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -330,6 +637,63 @@ class TimerCluster(private val controller: MatterController, private val endpoin return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -368,6 +732,63 @@ class TimerCluster(private val controller: MatterController, private val endpoin return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -399,6 +820,56 @@ class TimerCluster(private val controller: MatterController, private val endpoin return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -430,6 +901,58 @@ class TimerCluster(private val controller: MatterController, private val endpoin return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(TimerCluster::class.java.name) const val CLUSTER_ID: UInt = 71u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.kt index e5b5378056b324..5ff5251fad8295 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.FloatSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -33,22 +42,94 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( ) { class MeasuredValueAttribute(val value: Float?) + sealed class MeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MeasuredValueAttributeSubscriptionState() + } + class MinMeasuredValueAttribute(val value: Float?) + sealed class MinMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MinMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MinMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MinMeasuredValueAttributeSubscriptionState() + } + class MaxMeasuredValueAttribute(val value: Float?) + sealed class MaxMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : MaxMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : MaxMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : MaxMeasuredValueAttributeSubscriptionState() + } + class PeakMeasuredValueAttribute(val value: Float?) + sealed class PeakMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : PeakMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : PeakMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : PeakMeasuredValueAttributeSubscriptionState() + } + class AverageMeasuredValueAttribute(val value: Float?) + sealed class AverageMeasuredValueAttributeSubscriptionState { + data class Success(val value: Float?) : AverageMeasuredValueAttributeSubscriptionState() + + data class Error(val exception: Exception) : AverageMeasuredValueAttributeSubscriptionState() + + object SubscriptionEstablished : AverageMeasuredValueAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMeasuredValueAttribute(): MeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -90,6 +171,66 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return MeasuredValueAttribute(decodedValue) } + suspend fun subscribeMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Measuredvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMinMeasuredValueAttribute(): MinMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -131,6 +272,68 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return MinMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMinMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MinMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Minmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MinMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MinMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMaxMeasuredValueAttribute(): MaxMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -172,6 +375,68 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return MaxMeasuredValueAttribute(decodedValue) } + suspend fun subscribeMaxMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + MaxMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Maxmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(MaxMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(MaxMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueAttribute(): PeakMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -213,6 +478,68 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return PeakMeasuredValueAttribute(decodedValue) } + suspend fun subscribePeakMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PeakMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PeakMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PeakMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPeakMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 4u @@ -249,6 +576,63 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribePeakMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Peakmeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueAttribute(): AverageMeasuredValueAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -290,6 +674,68 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return AverageMeasuredValueAttribute(decodedValue) } + suspend fun subscribeAverageMeasuredValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AverageMeasuredValueAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvalue attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AverageMeasuredValueAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AverageMeasuredValueAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAverageMeasuredValueWindowAttribute(): UInt? { val ATTRIBUTE_ID: UInt = 6u @@ -326,6 +772,63 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeAverageMeasuredValueWindowAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Averagemeasuredvaluewindow attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UIntSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUncertaintyAttribute(): Float? { val ATTRIBUTE_ID: UInt = 7u @@ -362,6 +865,61 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeUncertaintyAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Uncertainty attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getFloat(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(FloatSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 8u @@ -398,6 +956,63 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readMeasurementMediumAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 9u @@ -434,6 +1049,63 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeMeasurementMediumAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Measurementmedium attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLevelValueAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 10u @@ -470,6 +1142,61 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeLevelValueAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Levelvalue attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -508,6 +1235,65 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -546,6 +1332,65 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -584,6 +1429,63 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -622,6 +1524,63 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -653,6 +1612,56 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -684,6 +1693,58 @@ class TotalVolatileOrganicCompoundsConcentrationMeasurementCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger( diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/UnitLocalizationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/UnitLocalizationCluster.kt index 2d18672a45c3a9..36c750385a9bd6 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/UnitLocalizationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/UnitLocalizationCluster.kt @@ -20,9 +20,16 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -38,12 +45,44 @@ class UnitLocalizationCluster( ) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readTemperatureUnitAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 0u @@ -120,6 +159,63 @@ class UnitLocalizationCluster( } } + suspend fun subscribeTemperatureUnitAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Temperatureunit attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -158,6 +254,65 @@ class UnitLocalizationCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -196,6 +351,65 @@ class UnitLocalizationCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -234,6 +448,63 @@ class UnitLocalizationCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -272,6 +543,63 @@ class UnitLocalizationCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -303,6 +631,56 @@ class UnitLocalizationCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -334,6 +712,58 @@ class UnitLocalizationCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(UnitLocalizationCluster::class.java.name) const val CLUSTER_ID: UInt = 45u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/UnitTestingCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/UnitTestingCluster.kt index e4961f84edc106..94fe39115cd7a2 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/UnitTestingCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/UnitTestingCluster.kt @@ -20,11 +20,28 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.BooleanSubscriptionState +import matter.controller.ByteArraySubscriptionState +import matter.controller.ByteSubscriptionState +import matter.controller.DoubleSubscriptionState +import matter.controller.FloatSubscriptionState +import matter.controller.IntSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse +import matter.controller.LongSubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.ShortSubscriptionState +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.ULongSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -104,94 +121,460 @@ class UnitTestingCluster(private val controller: MatterController, private val e class ListInt8uAttribute(val value: List) + sealed class ListInt8uAttributeSubscriptionState { + data class Success(val value: List) : ListInt8uAttributeSubscriptionState() + + data class Error(val exception: Exception) : ListInt8uAttributeSubscriptionState() + + object SubscriptionEstablished : ListInt8uAttributeSubscriptionState() + } + class ListOctetStringAttribute(val value: List) + sealed class ListOctetStringAttributeSubscriptionState { + data class Success(val value: List) : ListOctetStringAttributeSubscriptionState() + + data class Error(val exception: Exception) : ListOctetStringAttributeSubscriptionState() + + object SubscriptionEstablished : ListOctetStringAttributeSubscriptionState() + } + class ListStructOctetStringAttribute(val value: List) + sealed class ListStructOctetStringAttributeSubscriptionState { + data class Success(val value: List) : + ListStructOctetStringAttributeSubscriptionState() + + data class Error(val exception: Exception) : ListStructOctetStringAttributeSubscriptionState() + + object SubscriptionEstablished : ListStructOctetStringAttributeSubscriptionState() + } + class ListNullablesAndOptionalsStructAttribute( val value: List ) + sealed class ListNullablesAndOptionalsStructAttributeSubscriptionState { + data class Success(val value: List) : + ListNullablesAndOptionalsStructAttributeSubscriptionState() + + data class Error(val exception: Exception) : + ListNullablesAndOptionalsStructAttributeSubscriptionState() + + object SubscriptionEstablished : ListNullablesAndOptionalsStructAttributeSubscriptionState() + } + class StructAttrAttribute(val value: UnitTestingClusterSimpleStruct) + sealed class StructAttrAttributeSubscriptionState { + data class Success(val value: UnitTestingClusterSimpleStruct) : + StructAttrAttributeSubscriptionState() + + data class Error(val exception: Exception) : StructAttrAttributeSubscriptionState() + + object SubscriptionEstablished : StructAttrAttributeSubscriptionState() + } + class ListLongOctetStringAttribute(val value: List) + sealed class ListLongOctetStringAttributeSubscriptionState { + data class Success(val value: List) : + ListLongOctetStringAttributeSubscriptionState() + + data class Error(val exception: Exception) : ListLongOctetStringAttributeSubscriptionState() + + object SubscriptionEstablished : ListLongOctetStringAttributeSubscriptionState() + } + class ListFabricScopedAttribute(val value: List) + sealed class ListFabricScopedAttributeSubscriptionState { + data class Success(val value: List) : + ListFabricScopedAttributeSubscriptionState() + + data class Error(val exception: Exception) : ListFabricScopedAttributeSubscriptionState() + + object SubscriptionEstablished : ListFabricScopedAttributeSubscriptionState() + } + class NullableBooleanAttribute(val value: Boolean?) + sealed class NullableBooleanAttributeSubscriptionState { + data class Success(val value: Boolean?) : NullableBooleanAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableBooleanAttributeSubscriptionState() + + object SubscriptionEstablished : NullableBooleanAttributeSubscriptionState() + } + class NullableBitmap8Attribute(val value: UByte?) + sealed class NullableBitmap8AttributeSubscriptionState { + data class Success(val value: UByte?) : NullableBitmap8AttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableBitmap8AttributeSubscriptionState() + + object SubscriptionEstablished : NullableBitmap8AttributeSubscriptionState() + } + class NullableBitmap16Attribute(val value: UShort?) + sealed class NullableBitmap16AttributeSubscriptionState { + data class Success(val value: UShort?) : NullableBitmap16AttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableBitmap16AttributeSubscriptionState() + + object SubscriptionEstablished : NullableBitmap16AttributeSubscriptionState() + } + class NullableBitmap32Attribute(val value: UInt?) + sealed class NullableBitmap32AttributeSubscriptionState { + data class Success(val value: UInt?) : NullableBitmap32AttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableBitmap32AttributeSubscriptionState() + + object SubscriptionEstablished : NullableBitmap32AttributeSubscriptionState() + } + class NullableBitmap64Attribute(val value: ULong?) + sealed class NullableBitmap64AttributeSubscriptionState { + data class Success(val value: ULong?) : NullableBitmap64AttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableBitmap64AttributeSubscriptionState() + + object SubscriptionEstablished : NullableBitmap64AttributeSubscriptionState() + } + class NullableInt8uAttribute(val value: UByte?) + sealed class NullableInt8uAttributeSubscriptionState { + data class Success(val value: UByte?) : NullableInt8uAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt8uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt8uAttributeSubscriptionState() + } + class NullableInt16uAttribute(val value: UShort?) + sealed class NullableInt16uAttributeSubscriptionState { + data class Success(val value: UShort?) : NullableInt16uAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt16uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt16uAttributeSubscriptionState() + } + class NullableInt24uAttribute(val value: UInt?) + sealed class NullableInt24uAttributeSubscriptionState { + data class Success(val value: UInt?) : NullableInt24uAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt24uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt24uAttributeSubscriptionState() + } + class NullableInt32uAttribute(val value: UInt?) + sealed class NullableInt32uAttributeSubscriptionState { + data class Success(val value: UInt?) : NullableInt32uAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt32uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt32uAttributeSubscriptionState() + } + class NullableInt40uAttribute(val value: ULong?) + sealed class NullableInt40uAttributeSubscriptionState { + data class Success(val value: ULong?) : NullableInt40uAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt40uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt40uAttributeSubscriptionState() + } + class NullableInt48uAttribute(val value: ULong?) + sealed class NullableInt48uAttributeSubscriptionState { + data class Success(val value: ULong?) : NullableInt48uAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt48uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt48uAttributeSubscriptionState() + } + class NullableInt56uAttribute(val value: ULong?) + sealed class NullableInt56uAttributeSubscriptionState { + data class Success(val value: ULong?) : NullableInt56uAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt56uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt56uAttributeSubscriptionState() + } + class NullableInt64uAttribute(val value: ULong?) + sealed class NullableInt64uAttributeSubscriptionState { + data class Success(val value: ULong?) : NullableInt64uAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt64uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt64uAttributeSubscriptionState() + } + class NullableInt8sAttribute(val value: Byte?) + sealed class NullableInt8sAttributeSubscriptionState { + data class Success(val value: Byte?) : NullableInt8sAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt8sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt8sAttributeSubscriptionState() + } + class NullableInt16sAttribute(val value: Short?) + sealed class NullableInt16sAttributeSubscriptionState { + data class Success(val value: Short?) : NullableInt16sAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt16sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt16sAttributeSubscriptionState() + } + class NullableInt24sAttribute(val value: Int?) + sealed class NullableInt24sAttributeSubscriptionState { + data class Success(val value: Int?) : NullableInt24sAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt24sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt24sAttributeSubscriptionState() + } + class NullableInt32sAttribute(val value: Int?) + sealed class NullableInt32sAttributeSubscriptionState { + data class Success(val value: Int?) : NullableInt32sAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt32sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt32sAttributeSubscriptionState() + } + class NullableInt40sAttribute(val value: Long?) + sealed class NullableInt40sAttributeSubscriptionState { + data class Success(val value: Long?) : NullableInt40sAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt40sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt40sAttributeSubscriptionState() + } + class NullableInt48sAttribute(val value: Long?) + sealed class NullableInt48sAttributeSubscriptionState { + data class Success(val value: Long?) : NullableInt48sAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt48sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt48sAttributeSubscriptionState() + } + class NullableInt56sAttribute(val value: Long?) + sealed class NullableInt56sAttributeSubscriptionState { + data class Success(val value: Long?) : NullableInt56sAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt56sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt56sAttributeSubscriptionState() + } + class NullableInt64sAttribute(val value: Long?) + sealed class NullableInt64sAttributeSubscriptionState { + data class Success(val value: Long?) : NullableInt64sAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableInt64sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableInt64sAttributeSubscriptionState() + } + class NullableEnum8Attribute(val value: UByte?) + sealed class NullableEnum8AttributeSubscriptionState { + data class Success(val value: UByte?) : NullableEnum8AttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableEnum8AttributeSubscriptionState() + + object SubscriptionEstablished : NullableEnum8AttributeSubscriptionState() + } + class NullableEnum16Attribute(val value: UShort?) + sealed class NullableEnum16AttributeSubscriptionState { + data class Success(val value: UShort?) : NullableEnum16AttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableEnum16AttributeSubscriptionState() + + object SubscriptionEstablished : NullableEnum16AttributeSubscriptionState() + } + class NullableFloatSingleAttribute(val value: Float?) + sealed class NullableFloatSingleAttributeSubscriptionState { + data class Success(val value: Float?) : NullableFloatSingleAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableFloatSingleAttributeSubscriptionState() + + object SubscriptionEstablished : NullableFloatSingleAttributeSubscriptionState() + } + class NullableFloatDoubleAttribute(val value: Double?) + sealed class NullableFloatDoubleAttributeSubscriptionState { + data class Success(val value: Double?) : NullableFloatDoubleAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableFloatDoubleAttributeSubscriptionState() + + object SubscriptionEstablished : NullableFloatDoubleAttributeSubscriptionState() + } + class NullableOctetStringAttribute(val value: ByteArray?) + sealed class NullableOctetStringAttributeSubscriptionState { + data class Success(val value: ByteArray?) : NullableOctetStringAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableOctetStringAttributeSubscriptionState() + + object SubscriptionEstablished : NullableOctetStringAttributeSubscriptionState() + } + class NullableCharStringAttribute(val value: String?) + sealed class NullableCharStringAttributeSubscriptionState { + data class Success(val value: String?) : NullableCharStringAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableCharStringAttributeSubscriptionState() + + object SubscriptionEstablished : NullableCharStringAttributeSubscriptionState() + } + class NullableEnumAttrAttribute(val value: UByte?) + sealed class NullableEnumAttrAttributeSubscriptionState { + data class Success(val value: UByte?) : NullableEnumAttrAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableEnumAttrAttributeSubscriptionState() + + object SubscriptionEstablished : NullableEnumAttrAttributeSubscriptionState() + } + class NullableStructAttribute(val value: UnitTestingClusterSimpleStruct?) + sealed class NullableStructAttributeSubscriptionState { + data class Success(val value: UnitTestingClusterSimpleStruct?) : + NullableStructAttributeSubscriptionState() + + data class Error(val exception: Exception) : NullableStructAttributeSubscriptionState() + + object SubscriptionEstablished : NullableStructAttributeSubscriptionState() + } + class NullableRangeRestrictedInt8uAttribute(val value: UByte?) + sealed class NullableRangeRestrictedInt8uAttributeSubscriptionState { + data class Success(val value: UByte?) : + NullableRangeRestrictedInt8uAttributeSubscriptionState() + + data class Error(val exception: Exception) : + NullableRangeRestrictedInt8uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableRangeRestrictedInt8uAttributeSubscriptionState() + } + class NullableRangeRestrictedInt8sAttribute(val value: Byte?) + sealed class NullableRangeRestrictedInt8sAttributeSubscriptionState { + data class Success(val value: Byte?) : NullableRangeRestrictedInt8sAttributeSubscriptionState() + + data class Error(val exception: Exception) : + NullableRangeRestrictedInt8sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableRangeRestrictedInt8sAttributeSubscriptionState() + } + class NullableRangeRestrictedInt16uAttribute(val value: UShort?) + sealed class NullableRangeRestrictedInt16uAttributeSubscriptionState { + data class Success(val value: UShort?) : + NullableRangeRestrictedInt16uAttributeSubscriptionState() + + data class Error(val exception: Exception) : + NullableRangeRestrictedInt16uAttributeSubscriptionState() + + object SubscriptionEstablished : NullableRangeRestrictedInt16uAttributeSubscriptionState() + } + class NullableRangeRestrictedInt16sAttribute(val value: Short?) + sealed class NullableRangeRestrictedInt16sAttributeSubscriptionState { + data class Success(val value: Short?) : + NullableRangeRestrictedInt16sAttributeSubscriptionState() + + data class Error(val exception: Exception) : + NullableRangeRestrictedInt16sAttributeSubscriptionState() + + object SubscriptionEstablished : NullableRangeRestrictedInt16sAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun test(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -1905,6 +2288,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeBooleanAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Boolean attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBitmap8Attribute(): UByte { val ATTRIBUTE_ID: UInt = 1u @@ -1976,6 +2409,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeBitmap8Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Bitmap8 attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBitmap16Attribute(): UShort { val ATTRIBUTE_ID: UInt = 2u @@ -2047,6 +2530,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeBitmap16Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Bitmap16 attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBitmap32Attribute(): UInt { val ATTRIBUTE_ID: UInt = 3u @@ -2118,6 +2651,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeBitmap32Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Bitmap32 attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBitmap64Attribute(): ULong { val ATTRIBUTE_ID: UInt = 4u @@ -2189,6 +2772,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeBitmap64Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Bitmap64 attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong = tlvReader.getULong(AnonymousTag) + + emit(ULongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt8uAttribute(): UByte { val ATTRIBUTE_ID: UInt = 5u @@ -2260,6 +2893,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt8uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int8u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt16uAttribute(): UShort { val ATTRIBUTE_ID: UInt = 6u @@ -2331,6 +3014,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt16uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int16u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt24uAttribute(): UInt { val ATTRIBUTE_ID: UInt = 7u @@ -2402,6 +3135,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt24uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int24u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt32uAttribute(): UInt { val ATTRIBUTE_ID: UInt = 8u @@ -2473,6 +3256,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt32uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int32u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt40uAttribute(): ULong { val ATTRIBUTE_ID: UInt = 9u @@ -2544,6 +3377,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt40uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int40u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong = tlvReader.getULong(AnonymousTag) + + emit(ULongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt48uAttribute(): ULong { val ATTRIBUTE_ID: UInt = 10u @@ -2615,6 +3498,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt48uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int48u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong = tlvReader.getULong(AnonymousTag) + + emit(ULongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt56uAttribute(): ULong { val ATTRIBUTE_ID: UInt = 11u @@ -2686,6 +3619,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt56uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int56u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong = tlvReader.getULong(AnonymousTag) + + emit(ULongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt64uAttribute(): ULong { val ATTRIBUTE_ID: UInt = 12u @@ -2757,6 +3740,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt64uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int64u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong = tlvReader.getULong(AnonymousTag) + + emit(ULongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt8sAttribute(): Byte { val ATTRIBUTE_ID: UInt = 13u @@ -2828,6 +3861,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt8sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 13u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int8s attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte = tlvReader.getByte(AnonymousTag) + + emit(ByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt16sAttribute(): Short { val ATTRIBUTE_ID: UInt = 14u @@ -2899,6 +3982,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt16sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 14u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int16s attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short = tlvReader.getShort(AnonymousTag) + + emit(ShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt24sAttribute(): Int { val ATTRIBUTE_ID: UInt = 15u @@ -2970,6 +4103,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt24sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 15u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + IntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int24s attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Int = tlvReader.getInt(AnonymousTag) + + emit(IntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(IntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt32sAttribute(): Int { val ATTRIBUTE_ID: UInt = 16u @@ -3041,6 +4224,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt32sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + IntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int32s attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Int = tlvReader.getInt(AnonymousTag) + + emit(IntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(IntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt40sAttribute(): Long { val ATTRIBUTE_ID: UInt = 17u @@ -3112,6 +4345,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt40sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int40s attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long = tlvReader.getLong(AnonymousTag) + + emit(LongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt48sAttribute(): Long { val ATTRIBUTE_ID: UInt = 18u @@ -3183,6 +4466,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt48sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int48s attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long = tlvReader.getLong(AnonymousTag) + + emit(LongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt56sAttribute(): Long { val ATTRIBUTE_ID: UInt = 19u @@ -3254,6 +4587,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt56sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int56s attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long = tlvReader.getLong(AnonymousTag) + + emit(LongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInt64sAttribute(): Long { val ATTRIBUTE_ID: UInt = 20u @@ -3325,6 +4708,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeInt64sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 20u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Int64s attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long = tlvReader.getLong(AnonymousTag) + + emit(LongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEnum8Attribute(): UByte { val ATTRIBUTE_ID: UInt = 21u @@ -3396,6 +4829,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeEnum8Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 21u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Enum8 attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEnum16Attribute(): UShort { val ATTRIBUTE_ID: UInt = 22u @@ -3467,6 +4950,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeEnum16Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 22u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Enum16 attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFloatSingleAttribute(): Float { val ATTRIBUTE_ID: UInt = 23u @@ -3538,6 +5071,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeFloatSingleAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 23u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + FloatSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Floatsingle attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float = tlvReader.getFloat(AnonymousTag) + + emit(FloatSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(FloatSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFloatDoubleAttribute(): Double { val ATTRIBUTE_ID: UInt = 24u @@ -3609,6 +5192,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeFloatDoubleAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 24u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + DoubleSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Floatdouble attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Double = tlvReader.getDouble(AnonymousTag) + + emit(DoubleSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(DoubleSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOctetStringAttribute(): ByteArray { val ATTRIBUTE_ID: UInt = 25u @@ -3680,6 +5313,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeOctetStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 25u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteArraySubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Octetstring attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray = tlvReader.getByteArray(AnonymousTag) + + emit(ByteArraySubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteArraySubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readListInt8uAttribute(): ListInt8uAttribute { val ATTRIBUTE_ID: UInt = 26u @@ -3762,6 +5445,63 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeListInt8uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 26u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ListInt8uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Listint8u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUByte(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(ListInt8uAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ListInt8uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readListOctetStringAttribute(): ListOctetStringAttribute { val ATTRIBUTE_ID: UInt = 27u @@ -3847,6 +5587,65 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeListOctetStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 27u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ListOctetStringAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Listoctetstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getByteArray(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(ListOctetStringAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ListOctetStringAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readListStructOctetStringAttribute(): ListStructOctetStringAttribute { val ATTRIBUTE_ID: UInt = 28u @@ -3932,6 +5731,65 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeListStructOctetStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 28u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ListStructOctetStringAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Liststructoctetstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(UnitTestingClusterTestListStructOctet.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(ListStructOctetStringAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ListStructOctetStringAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLongOctetStringAttribute(): ByteArray { val ATTRIBUTE_ID: UInt = 29u @@ -4003,6 +5861,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeLongOctetStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 29u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteArraySubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Longoctetstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray = tlvReader.getByteArray(AnonymousTag) + + emit(ByteArraySubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteArraySubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCharStringAttribute(): String { val ATTRIBUTE_ID: UInt = 30u @@ -4074,6 +5984,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeCharStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 30u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Charstring attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLongCharStringAttribute(): String { val ATTRIBUTE_ID: UInt = 31u @@ -4145,6 +6105,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeLongCharStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 31u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Longcharstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String = tlvReader.getString(AnonymousTag) + + emit(StringSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEpochUsAttribute(): ULong { val ATTRIBUTE_ID: UInt = 32u @@ -4216,6 +6228,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeEpochUsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 32u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ULongSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Epochus attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong = tlvReader.getULong(AnonymousTag) + + emit(ULongSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ULongSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEpochSAttribute(): UInt { val ATTRIBUTE_ID: UInt = 33u @@ -4287,6 +6349,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeEpochSAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 33u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Epochs attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readVendorIdAttribute(): UShort { val ATTRIBUTE_ID: UInt = 34u @@ -4358,6 +6470,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeVendorIdAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 34u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Vendorid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readListNullablesAndOptionalsStructAttribute(): ListNullablesAndOptionalsStructAttribute { val ATTRIBUTE_ID: UInt = 35u @@ -4446,6 +6608,65 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeListNullablesAndOptionalsStructAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 35u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ListNullablesAndOptionalsStructAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Listnullablesandoptionalsstruct attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(UnitTestingClusterNullablesAndOptionalsStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(ListNullablesAndOptionalsStructAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ListNullablesAndOptionalsStructAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEnumAttrAttribute(): UByte { val ATTRIBUTE_ID: UInt = 36u @@ -4517,13 +6738,63 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } - suspend fun readStructAttrAttribute(): StructAttrAttribute { - val ATTRIBUTE_ID: UInt = 37u + suspend fun subscribeEnumAttrAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 36u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) - val attributePath = - AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) - val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Enumattr attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readStructAttrAttribute(): StructAttrAttribute { + val ATTRIBUTE_ID: UInt = 37u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) val response = controller.read(readRequest) @@ -4592,6 +6863,57 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeStructAttrAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 37u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StructAttrAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Structattr attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UnitTestingClusterSimpleStruct = + UnitTestingClusterSimpleStruct.fromTlv(AnonymousTag, tlvReader) + + emit(StructAttrAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(StructAttrAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRangeRestrictedInt8uAttribute(): UByte { val ATTRIBUTE_ID: UInt = 38u @@ -4666,6 +6988,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeRangeRestrictedInt8uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 38u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rangerestrictedint8u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRangeRestrictedInt8sAttribute(): Byte { val ATTRIBUTE_ID: UInt = 39u @@ -4737,6 +7111,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeRangeRestrictedInt8sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 39u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rangerestrictedint8s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte = tlvReader.getByte(AnonymousTag) + + emit(ByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRangeRestrictedInt16uAttribute(): UShort { val ATTRIBUTE_ID: UInt = 40u @@ -4811,6 +7237,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeRangeRestrictedInt16uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 40u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rangerestrictedint16u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRangeRestrictedInt16sAttribute(): Short { val ATTRIBUTE_ID: UInt = 41u @@ -4885,6 +7363,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeRangeRestrictedInt16sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 41u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Rangerestrictedint16s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short = tlvReader.getShort(AnonymousTag) + + emit(ShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readListLongOctetStringAttribute(): ListLongOctetStringAttribute { val ATTRIBUTE_ID: UInt = 42u @@ -4970,6 +7500,65 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeListLongOctetStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 42u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ListLongOctetStringAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Listlongoctetstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getByteArray(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(ListLongOctetStringAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ListLongOctetStringAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readListFabricScopedAttribute(): ListFabricScopedAttribute { val ATTRIBUTE_ID: UInt = 43u @@ -5055,6 +7644,65 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeListFabricScopedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 43u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ListFabricScopedAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Listfabricscoped attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(UnitTestingClusterTestFabricScoped.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(ListFabricScopedAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(ListFabricScopedAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTimedWriteBooleanAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 48u @@ -5126,6 +7774,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeTimedWriteBooleanAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 48u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Timedwriteboolean attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneralErrorBooleanAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 49u @@ -5200,6 +7900,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeGeneralErrorBooleanAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 49u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generalerrorboolean attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterErrorBooleanAttribute(): Boolean { val ATTRIBUTE_ID: UInt = 50u @@ -5274,6 +8026,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeClusterErrorBooleanAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 50u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clustererrorboolean attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean = tlvReader.getBoolean(AnonymousTag) + + emit(BooleanSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readUnsupportedAttribute(): Boolean? { val ATTRIBUTE_ID: UInt = 255u @@ -5350,6 +8154,61 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeUnsupportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 255u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BooleanSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Unsupported attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getBoolean(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BooleanSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableBooleanAttribute(): NullableBooleanAttribute { val ATTRIBUTE_ID: UInt = 16384u @@ -5427,6 +8286,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableBooleanAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16384u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableBooleanAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableboolean attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Boolean? = + if (!tlvReader.isNull()) { + tlvReader.getBoolean(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableBooleanAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableBooleanAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableBitmap8Attribute(): NullableBitmap8Attribute { val ATTRIBUTE_ID: UInt = 16385u @@ -5504,6 +8421,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableBitmap8Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16385u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableBitmap8AttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablebitmap8 attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableBitmap8AttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableBitmap8AttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableBitmap16Attribute(): NullableBitmap16Attribute { val ATTRIBUTE_ID: UInt = 16386u @@ -5581,19 +8556,77 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } - suspend fun readNullableBitmap32Attribute(): NullableBitmap32Attribute { - val ATTRIBUTE_ID: UInt = 16387u + suspend fun subscribeNullableBitmap16Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16386u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) - val attributePath = - AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) - val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableBitmap16AttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablebitmap16 attribute not found in Node State update" + } - val response = controller.read(readRequest) + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } - if (response.successes.isEmpty()) { - logger.log(Level.WARNING, "Read command failed") - throw IllegalStateException("Read command failed with failures: ${response.failures}") + decodedValue?.let { emit(NullableBitmap16AttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableBitmap16AttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readNullableBitmap32Attribute(): NullableBitmap32Attribute { + val ATTRIBUTE_ID: UInt = 16387u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") } logger.log(Level.FINE, "Read command succeeded") @@ -5658,6 +8691,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableBitmap32Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16387u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableBitmap32AttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablebitmap32 attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + tlvReader.getUInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableBitmap32AttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableBitmap32AttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableBitmap64Attribute(): NullableBitmap64Attribute { val ATTRIBUTE_ID: UInt = 16388u @@ -5735,6 +8826,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableBitmap64Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16388u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableBitmap64AttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablebitmap64 attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + tlvReader.getULong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableBitmap64AttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableBitmap64AttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt8uAttribute(): NullableInt8uAttribute { val ATTRIBUTE_ID: UInt = 16389u @@ -5812,6 +8961,62 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt8uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16389u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt8uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Nullableint8u attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt8uAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt8uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt16uAttribute(): NullableInt16uAttribute { val ATTRIBUTE_ID: UInt = 16390u @@ -5889,6 +9094,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt16uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16390u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt16uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint16u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt16uAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt16uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt24uAttribute(): NullableInt24uAttribute { val ATTRIBUTE_ID: UInt = 16391u @@ -5966,6 +9229,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt24uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16391u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt24uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint24u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + tlvReader.getUInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt24uAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt24uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt32uAttribute(): NullableInt32uAttribute { val ATTRIBUTE_ID: UInt = 16392u @@ -6043,6 +9364,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt32uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16392u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt32uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint32u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + tlvReader.getUInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt32uAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt32uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt40uAttribute(): NullableInt40uAttribute { val ATTRIBUTE_ID: UInt = 16393u @@ -6120,6 +9499,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt40uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16393u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt40uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint40u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + tlvReader.getULong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt40uAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt40uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt48uAttribute(): NullableInt48uAttribute { val ATTRIBUTE_ID: UInt = 16394u @@ -6197,6 +9634,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt48uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16394u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt48uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint48u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + tlvReader.getULong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt48uAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt48uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt56uAttribute(): NullableInt56uAttribute { val ATTRIBUTE_ID: UInt = 16395u @@ -6274,6 +9769,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt56uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16395u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt56uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint56u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + tlvReader.getULong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt56uAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt56uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt64uAttribute(): NullableInt64uAttribute { val ATTRIBUTE_ID: UInt = 16396u @@ -6351,6 +9904,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt64uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16396u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt64uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint64u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + tlvReader.getULong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt64uAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt64uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt8sAttribute(): NullableInt8sAttribute { val ATTRIBUTE_ID: UInt = 16397u @@ -6428,6 +10039,62 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt8sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16397u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt8sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Nullableint8s attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (!tlvReader.isNull()) { + tlvReader.getByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt8sAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt8sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt16sAttribute(): NullableInt16sAttribute { val ATTRIBUTE_ID: UInt = 16398u @@ -6505,17 +10172,75 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } - suspend fun readNullableInt24sAttribute(): NullableInt24sAttribute { - val ATTRIBUTE_ID: UInt = 16399u + suspend fun subscribeNullableInt16sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16398u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) - val attributePath = - AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) - val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt16sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint16s attribute not found in Node State update" + } - val response = controller.read(readRequest) + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } - if (response.successes.isEmpty()) { + decodedValue?.let { emit(NullableInt16sAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt16sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readNullableInt24sAttribute(): NullableInt24sAttribute { + val ATTRIBUTE_ID: UInt = 16399u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { logger.log(Level.WARNING, "Read command failed") throw IllegalStateException("Read command failed with failures: ${response.failures}") } @@ -6582,6 +10307,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt24sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16399u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt24sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint24s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Int? = + if (!tlvReader.isNull()) { + tlvReader.getInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt24sAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt24sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt32sAttribute(): NullableInt32sAttribute { val ATTRIBUTE_ID: UInt = 16400u @@ -6659,6 +10442,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt32sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16400u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt32sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint32s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Int? = + if (!tlvReader.isNull()) { + tlvReader.getInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt32sAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt32sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt40sAttribute(): NullableInt40sAttribute { val ATTRIBUTE_ID: UInt = 16401u @@ -6736,6 +10577,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt40sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16401u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt40sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint40s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (!tlvReader.isNull()) { + tlvReader.getLong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt40sAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt40sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt48sAttribute(): NullableInt48sAttribute { val ATTRIBUTE_ID: UInt = 16402u @@ -6813,6 +10712,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt48sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16402u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt48sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint48s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (!tlvReader.isNull()) { + tlvReader.getLong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt48sAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt48sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt56sAttribute(): NullableInt56sAttribute { val ATTRIBUTE_ID: UInt = 16403u @@ -6890,6 +10847,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt56sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16403u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt56sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint56s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (!tlvReader.isNull()) { + tlvReader.getLong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt56sAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt56sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableInt64sAttribute(): NullableInt64sAttribute { val ATTRIBUTE_ID: UInt = 16404u @@ -6967,6 +10982,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableInt64sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16404u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableInt64sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableint64s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Long? = + if (!tlvReader.isNull()) { + tlvReader.getLong(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableInt64sAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableInt64sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableEnum8Attribute(): NullableEnum8Attribute { val ATTRIBUTE_ID: UInt = 16405u @@ -7044,6 +11117,62 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableEnum8Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16405u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableEnum8AttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Nullableenum8 attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableEnum8AttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableEnum8AttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableEnum16Attribute(): NullableEnum16Attribute { val ATTRIBUTE_ID: UInt = 16406u @@ -7121,6 +11250,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableEnum16Attribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16406u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableEnum16AttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableenum16 attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableEnum16AttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableEnum16AttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableFloatSingleAttribute(): NullableFloatSingleAttribute { val ATTRIBUTE_ID: UInt = 16407u @@ -7198,6 +11385,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableFloatSingleAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16407u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableFloatSingleAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablefloatsingle attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Float? = + if (!tlvReader.isNull()) { + tlvReader.getFloat(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableFloatSingleAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableFloatSingleAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableFloatDoubleAttribute(): NullableFloatDoubleAttribute { val ATTRIBUTE_ID: UInt = 16408u @@ -7278,6 +11523,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableFloatDoubleAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16408u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableFloatDoubleAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablefloatdouble attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Double? = + if (!tlvReader.isNull()) { + tlvReader.getDouble(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableFloatDoubleAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableFloatDoubleAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableOctetStringAttribute(): NullableOctetStringAttribute { val ATTRIBUTE_ID: UInt = 16409u @@ -7358,6 +11661,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableOctetStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16409u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableOctetStringAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableoctetstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray? = + if (!tlvReader.isNull()) { + tlvReader.getByteArray(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableOctetStringAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableOctetStringAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableCharStringAttribute(): NullableCharStringAttribute { val ATTRIBUTE_ID: UInt = 16414u @@ -7435,6 +11796,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableCharStringAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16414u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableCharStringAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablecharstring attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (!tlvReader.isNull()) { + tlvReader.getString(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableCharStringAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableCharStringAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableEnumAttrAttribute(): NullableEnumAttrAttribute { val ATTRIBUTE_ID: UInt = 16420u @@ -7512,6 +11931,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableEnumAttrAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16420u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableEnumAttrAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullableenumattr attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableEnumAttrAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableEnumAttrAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableStructAttribute(): NullableStructAttribute { val ATTRIBUTE_ID: UInt = 16421u @@ -7592,6 +12069,64 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableStructAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16421u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableStructAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablestruct attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UnitTestingClusterSimpleStruct? = + if (!tlvReader.isNull()) { + UnitTestingClusterSimpleStruct.fromTlv(AnonymousTag, tlvReader) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(NullableStructAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableStructAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableRangeRestrictedInt8uAttribute(): NullableRangeRestrictedInt8uAttribute { val ATTRIBUTE_ID: UInt = 16422u @@ -7672,6 +12207,66 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableRangeRestrictedInt8uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16422u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableRangeRestrictedInt8uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablerangerestrictedint8u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(NullableRangeRestrictedInt8uAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableRangeRestrictedInt8uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableRangeRestrictedInt8sAttribute(): NullableRangeRestrictedInt8sAttribute { val ATTRIBUTE_ID: UInt = 16423u @@ -7752,6 +12347,66 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableRangeRestrictedInt8sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16423u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableRangeRestrictedInt8sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablerangerestrictedint8s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (!tlvReader.isNull()) { + tlvReader.getByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(NullableRangeRestrictedInt8sAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableRangeRestrictedInt8sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableRangeRestrictedInt16uAttribute(): NullableRangeRestrictedInt16uAttribute { val ATTRIBUTE_ID: UInt = 16424u @@ -7834,6 +12489,66 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableRangeRestrictedInt16uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16424u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableRangeRestrictedInt16uAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablerangerestrictedint16u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(NullableRangeRestrictedInt16uAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableRangeRestrictedInt16uAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNullableRangeRestrictedInt16sAttribute(): NullableRangeRestrictedInt16sAttribute { val ATTRIBUTE_ID: UInt = 16425u @@ -7916,6 +12631,66 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeNullableRangeRestrictedInt16sAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16425u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + NullableRangeRestrictedInt16sAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Nullablerangerestrictedint16s attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Short? = + if (!tlvReader.isNull()) { + tlvReader.getShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(NullableRangeRestrictedInt16sAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(NullableRangeRestrictedInt16sAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWriteOnlyInt8uAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 16426u @@ -7992,6 +12767,63 @@ class UnitTestingCluster(private val controller: MatterController, private val e } } + suspend fun subscribeWriteOnlyInt8uAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16426u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Writeonlyint8u attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -8030,6 +12862,65 @@ class UnitTestingCluster(private val controller: MatterController, private val e return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -8068,6 +12959,65 @@ class UnitTestingCluster(private val controller: MatterController, private val e return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -8106,6 +13056,63 @@ class UnitTestingCluster(private val controller: MatterController, private val e return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -8144,6 +13151,63 @@ class UnitTestingCluster(private val controller: MatterController, private val e return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -8175,6 +13239,56 @@ class UnitTestingCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -8206,6 +13320,58 @@ class UnitTestingCluster(private val controller: MatterController, private val e return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(UnitTestingCluster::class.java.name) const val CLUSTER_ID: UInt = 4294048773u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/UserLabelCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/UserLabelCluster.kt index 949d2b8dd1670f..df0867a6902b61 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/UserLabelCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/UserLabelCluster.kt @@ -20,9 +20,15 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -35,14 +41,55 @@ import matter.tlv.TlvWriter class UserLabelCluster(private val controller: MatterController, private val endpointId: UShort) { class LabelListAttribute(val value: List) + sealed class LabelListAttributeSubscriptionState { + data class Success(val value: List) : + LabelListAttributeSubscriptionState() + + data class Error(val exception: Exception) : LabelListAttributeSubscriptionState() + + object SubscriptionEstablished : LabelListAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readLabelListAttribute(): LabelListAttribute { val ATTRIBUTE_ID: UInt = 0u @@ -128,6 +175,63 @@ class UserLabelCluster(private val controller: MatterController, private val end } } + suspend fun subscribeLabelListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + LabelListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Labellist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(UserLabelClusterLabelStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + + emit(LabelListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(LabelListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -166,6 +270,65 @@ class UserLabelCluster(private val controller: MatterController, private val end return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -204,6 +367,65 @@ class UserLabelCluster(private val controller: MatterController, private val end return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -242,6 +464,63 @@ class UserLabelCluster(private val controller: MatterController, private val end return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -280,6 +559,63 @@ class UserLabelCluster(private val controller: MatterController, private val end return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -311,6 +647,56 @@ class UserLabelCluster(private val controller: MatterController, private val end return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -342,6 +728,58 @@ class UserLabelCluster(private val controller: MatterController, private val end return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(UserLabelCluster::class.java.name) const val CLUSTER_ID: UInt = 65u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ValveConfigurationAndControlCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ValveConfigurationAndControlCluster.kt index b3d2e536513087..1ca214354c7f19 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ValveConfigurationAndControlCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ValveConfigurationAndControlCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -42,28 +49,124 @@ class ValveConfigurationAndControlCluster( ) { class OpenDurationAttribute(val value: UInt?) + sealed class OpenDurationAttributeSubscriptionState { + data class Success(val value: UInt?) : OpenDurationAttributeSubscriptionState() + + data class Error(val exception: Exception) : OpenDurationAttributeSubscriptionState() + + object SubscriptionEstablished : OpenDurationAttributeSubscriptionState() + } + class AutoCloseTimeAttribute(val value: ULong?) + sealed class AutoCloseTimeAttributeSubscriptionState { + data class Success(val value: ULong?) : AutoCloseTimeAttributeSubscriptionState() + + data class Error(val exception: Exception) : AutoCloseTimeAttributeSubscriptionState() + + object SubscriptionEstablished : AutoCloseTimeAttributeSubscriptionState() + } + class RemainingDurationAttribute(val value: UInt?) + sealed class RemainingDurationAttributeSubscriptionState { + data class Success(val value: UInt?) : RemainingDurationAttributeSubscriptionState() + + data class Error(val exception: Exception) : RemainingDurationAttributeSubscriptionState() + + object SubscriptionEstablished : RemainingDurationAttributeSubscriptionState() + } + class CurrentStateAttribute(val value: UByte?) + sealed class CurrentStateAttributeSubscriptionState { + data class Success(val value: UByte?) : CurrentStateAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentStateAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentStateAttributeSubscriptionState() + } + class TargetStateAttribute(val value: UByte?) + sealed class TargetStateAttributeSubscriptionState { + data class Success(val value: UByte?) : TargetStateAttributeSubscriptionState() + + data class Error(val exception: Exception) : TargetStateAttributeSubscriptionState() + + object SubscriptionEstablished : TargetStateAttributeSubscriptionState() + } + class CurrentLevelAttribute(val value: UByte?) + sealed class CurrentLevelAttributeSubscriptionState { + data class Success(val value: UByte?) : CurrentLevelAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentLevelAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentLevelAttributeSubscriptionState() + } + class TargetLevelAttribute(val value: UByte?) + sealed class TargetLevelAttributeSubscriptionState { + data class Success(val value: UByte?) : TargetLevelAttributeSubscriptionState() + + data class Error(val exception: Exception) : TargetLevelAttributeSubscriptionState() + + object SubscriptionEstablished : TargetLevelAttributeSubscriptionState() + } + class OpenLevelAttribute(val value: UByte?) + sealed class OpenLevelAttributeSubscriptionState { + data class Success(val value: UByte?) : OpenLevelAttributeSubscriptionState() + + data class Error(val exception: Exception) : OpenLevelAttributeSubscriptionState() + + object SubscriptionEstablished : OpenLevelAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun open(openDuration: UInt?, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -204,6 +307,62 @@ class ValveConfigurationAndControlCluster( } } + suspend fun subscribeOpenDurationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OpenDurationAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Openduration attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + tlvReader.getUInt(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OpenDurationAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OpenDurationAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAutoCloseTimeAttribute(): AutoCloseTimeAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -245,6 +404,66 @@ class ValveConfigurationAndControlCluster( return AutoCloseTimeAttribute(decodedValue) } + suspend fun subscribeAutoCloseTimeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AutoCloseTimeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Autoclosetime attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(AutoCloseTimeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(AutoCloseTimeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRemainingDurationAttribute(): RemainingDurationAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -286,6 +505,68 @@ class ValveConfigurationAndControlCluster( return RemainingDurationAttribute(decodedValue) } + suspend fun subscribeRemainingDurationAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + RemainingDurationAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Remainingduration attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(RemainingDurationAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(RemainingDurationAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentStateAttribute(): CurrentStateAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -323,6 +604,62 @@ class ValveConfigurationAndControlCluster( return CurrentStateAttribute(decodedValue) } + suspend fun subscribeCurrentStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentStateAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentstate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentStateAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentStateAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTargetStateAttribute(): TargetStateAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -360,6 +697,62 @@ class ValveConfigurationAndControlCluster( return TargetStateAttribute(decodedValue) } + suspend fun subscribeTargetStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TargetStateAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Targetstate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(TargetStateAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(TargetStateAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readStartUpStateAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 5u @@ -436,6 +829,61 @@ class ValveConfigurationAndControlCluster( } } + suspend fun subscribeStartUpStateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Startupstate attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentLevelAttribute(): CurrentLevelAttribute { val ATTRIBUTE_ID: UInt = 6u @@ -477,6 +925,66 @@ class ValveConfigurationAndControlCluster( return CurrentLevelAttribute(decodedValue) } + suspend fun subscribeCurrentLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentLevelAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Currentlevel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentLevelAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentLevelAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTargetLevelAttribute(): TargetLevelAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -518,6 +1026,66 @@ class ValveConfigurationAndControlCluster( return TargetLevelAttribute(decodedValue) } + suspend fun subscribeTargetLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TargetLevelAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Targetlevel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(TargetLevelAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(TargetLevelAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOpenLevelAttribute(): OpenLevelAttribute { val ATTRIBUTE_ID: UInt = 8u @@ -599,6 +1167,66 @@ class ValveConfigurationAndControlCluster( } } + suspend fun subscribeOpenLevelAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OpenLevelAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Openlevel attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OpenLevelAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OpenLevelAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readValveFaultAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 9u @@ -635,6 +1263,61 @@ class ValveConfigurationAndControlCluster( return decodedValue } + suspend fun subscribeValveFaultAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Valvefault attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -673,6 +1356,65 @@ class ValveConfigurationAndControlCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -711,6 +1453,65 @@ class ValveConfigurationAndControlCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -749,6 +1550,63 @@ class ValveConfigurationAndControlCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -787,6 +1645,63 @@ class ValveConfigurationAndControlCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -818,6 +1733,56 @@ class ValveConfigurationAndControlCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -849,6 +1814,58 @@ class ValveConfigurationAndControlCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(ValveConfigurationAndControlCluster::class.java.name) const val CLUSTER_ID: UInt = 129u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/WakeOnLanCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/WakeOnLanCluster.kt index 982b3d6118f1a7..b29d8ae7c59bd6 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/WakeOnLanCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/WakeOnLanCluster.kt @@ -17,11 +17,20 @@ package matter.controller.cluster.clusters +import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform +import matter.controller.ByteArraySubscriptionState import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.StringSubscriptionState +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.tlv.AnonymousTag @@ -30,12 +39,44 @@ import matter.tlv.TlvReader class WakeOnLanCluster(private val controller: MatterController, private val endpointId: UShort) { class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun readMACAddressAttribute(): String? { val ATTRIBUTE_ID: UInt = 0u @@ -72,6 +113,61 @@ class WakeOnLanCluster(private val controller: MatterController, private val end return decodedValue } + suspend fun subscribeMACAddressAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + StringSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Macaddress attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: String? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getString(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(StringSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(StringSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readLinkLocalAddressAttribute(): ByteArray? { val ATTRIBUTE_ID: UInt = 1u @@ -108,6 +204,63 @@ class WakeOnLanCluster(private val controller: MatterController, private val end return decodedValue } + suspend fun subscribeLinkLocalAddressAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ByteArraySubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Linklocaladdress attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getByteArray(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(ByteArraySubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ByteArraySubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -146,6 +299,65 @@ class WakeOnLanCluster(private val controller: MatterController, private val end return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -184,6 +396,65 @@ class WakeOnLanCluster(private val controller: MatterController, private val end return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -222,6 +493,63 @@ class WakeOnLanCluster(private val controller: MatterController, private val end return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -260,6 +588,63 @@ class WakeOnLanCluster(private val controller: MatterController, private val end return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -291,6 +676,56 @@ class WakeOnLanCluster(private val controller: MatterController, private val end return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -322,6 +757,58 @@ class WakeOnLanCluster(private val controller: MatterController, private val end return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(WakeOnLanCluster::class.java.name) const val CLUSTER_ID: UInt = 1283u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/WiFiNetworkDiagnosticsCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/WiFiNetworkDiagnosticsCluster.kt index 57eacac49efc59..a5a3c4300e4829 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/WiFiNetworkDiagnosticsCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/WiFiNetworkDiagnosticsCluster.kt @@ -20,11 +20,17 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.cluster.structs.* import matter.controller.model.AttributePath import matter.controller.model.CommandPath @@ -38,38 +44,174 @@ class WiFiNetworkDiagnosticsCluster( ) { class BssidAttribute(val value: ByteArray?) + sealed class BssidAttributeSubscriptionState { + data class Success(val value: ByteArray?) : BssidAttributeSubscriptionState() + + data class Error(val exception: Exception) : BssidAttributeSubscriptionState() + + object SubscriptionEstablished : BssidAttributeSubscriptionState() + } + class SecurityTypeAttribute(val value: UByte?) + sealed class SecurityTypeAttributeSubscriptionState { + data class Success(val value: UByte?) : SecurityTypeAttributeSubscriptionState() + + data class Error(val exception: Exception) : SecurityTypeAttributeSubscriptionState() + + object SubscriptionEstablished : SecurityTypeAttributeSubscriptionState() + } + class WiFiVersionAttribute(val value: UByte?) + sealed class WiFiVersionAttributeSubscriptionState { + data class Success(val value: UByte?) : WiFiVersionAttributeSubscriptionState() + + data class Error(val exception: Exception) : WiFiVersionAttributeSubscriptionState() + + object SubscriptionEstablished : WiFiVersionAttributeSubscriptionState() + } + class ChannelNumberAttribute(val value: UShort?) + sealed class ChannelNumberAttributeSubscriptionState { + data class Success(val value: UShort?) : ChannelNumberAttributeSubscriptionState() + + data class Error(val exception: Exception) : ChannelNumberAttributeSubscriptionState() + + object SubscriptionEstablished : ChannelNumberAttributeSubscriptionState() + } + class RssiAttribute(val value: Byte?) + sealed class RssiAttributeSubscriptionState { + data class Success(val value: Byte?) : RssiAttributeSubscriptionState() + + data class Error(val exception: Exception) : RssiAttributeSubscriptionState() + + object SubscriptionEstablished : RssiAttributeSubscriptionState() + } + class BeaconLostCountAttribute(val value: UInt?) + sealed class BeaconLostCountAttributeSubscriptionState { + data class Success(val value: UInt?) : BeaconLostCountAttributeSubscriptionState() + + data class Error(val exception: Exception) : BeaconLostCountAttributeSubscriptionState() + + object SubscriptionEstablished : BeaconLostCountAttributeSubscriptionState() + } + class BeaconRxCountAttribute(val value: UInt?) + sealed class BeaconRxCountAttributeSubscriptionState { + data class Success(val value: UInt?) : BeaconRxCountAttributeSubscriptionState() + + data class Error(val exception: Exception) : BeaconRxCountAttributeSubscriptionState() + + object SubscriptionEstablished : BeaconRxCountAttributeSubscriptionState() + } + class PacketMulticastRxCountAttribute(val value: UInt?) + sealed class PacketMulticastRxCountAttributeSubscriptionState { + data class Success(val value: UInt?) : PacketMulticastRxCountAttributeSubscriptionState() + + data class Error(val exception: Exception) : PacketMulticastRxCountAttributeSubscriptionState() + + object SubscriptionEstablished : PacketMulticastRxCountAttributeSubscriptionState() + } + class PacketMulticastTxCountAttribute(val value: UInt?) + sealed class PacketMulticastTxCountAttributeSubscriptionState { + data class Success(val value: UInt?) : PacketMulticastTxCountAttributeSubscriptionState() + + data class Error(val exception: Exception) : PacketMulticastTxCountAttributeSubscriptionState() + + object SubscriptionEstablished : PacketMulticastTxCountAttributeSubscriptionState() + } + class PacketUnicastRxCountAttribute(val value: UInt?) + sealed class PacketUnicastRxCountAttributeSubscriptionState { + data class Success(val value: UInt?) : PacketUnicastRxCountAttributeSubscriptionState() + + data class Error(val exception: Exception) : PacketUnicastRxCountAttributeSubscriptionState() + + object SubscriptionEstablished : PacketUnicastRxCountAttributeSubscriptionState() + } + class PacketUnicastTxCountAttribute(val value: UInt?) + sealed class PacketUnicastTxCountAttributeSubscriptionState { + data class Success(val value: UInt?) : PacketUnicastTxCountAttributeSubscriptionState() + + data class Error(val exception: Exception) : PacketUnicastTxCountAttributeSubscriptionState() + + object SubscriptionEstablished : PacketUnicastTxCountAttributeSubscriptionState() + } + class CurrentMaxRateAttribute(val value: ULong?) + sealed class CurrentMaxRateAttributeSubscriptionState { + data class Success(val value: ULong?) : CurrentMaxRateAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentMaxRateAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentMaxRateAttributeSubscriptionState() + } + class OverrunCountAttribute(val value: ULong?) + sealed class OverrunCountAttributeSubscriptionState { + data class Success(val value: ULong?) : OverrunCountAttributeSubscriptionState() + + data class Error(val exception: Exception) : OverrunCountAttributeSubscriptionState() + + object SubscriptionEstablished : OverrunCountAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun resetCounts(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -125,6 +267,62 @@ class WiFiNetworkDiagnosticsCluster( return BssidAttribute(decodedValue) } + suspend fun subscribeBssidAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BssidAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Bssid attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ByteArray? = + if (!tlvReader.isNull()) { + tlvReader.getByteArray(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BssidAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BssidAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSecurityTypeAttribute(): SecurityTypeAttribute { val ATTRIBUTE_ID: UInt = 1u @@ -162,6 +360,62 @@ class WiFiNetworkDiagnosticsCluster( return SecurityTypeAttribute(decodedValue) } + suspend fun subscribeSecurityTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + SecurityTypeAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Securitytype attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(SecurityTypeAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(SecurityTypeAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readWiFiVersionAttribute(): WiFiVersionAttribute { val ATTRIBUTE_ID: UInt = 2u @@ -199,6 +453,62 @@ class WiFiNetworkDiagnosticsCluster( return WiFiVersionAttribute(decodedValue) } + suspend fun subscribeWiFiVersionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + WiFiVersionAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Wifiversion attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + tlvReader.getUByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(WiFiVersionAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(WiFiVersionAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readChannelNumberAttribute(): ChannelNumberAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -236,6 +546,62 @@ class WiFiNetworkDiagnosticsCluster( return ChannelNumberAttribute(decodedValue) } + suspend fun subscribeChannelNumberAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + ChannelNumberAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Channelnumber attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + tlvReader.getUShort(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(ChannelNumberAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(ChannelNumberAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readRssiAttribute(): RssiAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -273,6 +639,62 @@ class WiFiNetworkDiagnosticsCluster( return RssiAttribute(decodedValue) } + suspend fun subscribeRssiAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + RssiAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Rssi attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: Byte? = + if (!tlvReader.isNull()) { + tlvReader.getByte(AnonymousTag) + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(RssiAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(RssiAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBeaconLostCountAttribute(): BeaconLostCountAttribute { val ATTRIBUTE_ID: UInt = 5u @@ -314,6 +736,68 @@ class WiFiNetworkDiagnosticsCluster( return BeaconLostCountAttribute(decodedValue) } + suspend fun subscribeBeaconLostCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BeaconLostCountAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Beaconlostcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BeaconLostCountAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BeaconLostCountAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readBeaconRxCountAttribute(): BeaconRxCountAttribute { val ATTRIBUTE_ID: UInt = 6u @@ -355,6 +839,66 @@ class WiFiNetworkDiagnosticsCluster( return BeaconRxCountAttribute(decodedValue) } + suspend fun subscribeBeaconRxCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + BeaconRxCountAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Beaconrxcount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(BeaconRxCountAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(BeaconRxCountAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPacketMulticastRxCountAttribute(): PacketMulticastRxCountAttribute { val ATTRIBUTE_ID: UInt = 7u @@ -396,6 +940,68 @@ class WiFiNetworkDiagnosticsCluster( return PacketMulticastRxCountAttribute(decodedValue) } + suspend fun subscribePacketMulticastRxCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PacketMulticastRxCountAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Packetmulticastrxcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PacketMulticastRxCountAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PacketMulticastRxCountAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPacketMulticastTxCountAttribute(): PacketMulticastTxCountAttribute { val ATTRIBUTE_ID: UInt = 8u @@ -437,6 +1043,68 @@ class WiFiNetworkDiagnosticsCluster( return PacketMulticastTxCountAttribute(decodedValue) } + suspend fun subscribePacketMulticastTxCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PacketMulticastTxCountAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Packetmulticasttxcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PacketMulticastTxCountAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PacketMulticastTxCountAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPacketUnicastRxCountAttribute(): PacketUnicastRxCountAttribute { val ATTRIBUTE_ID: UInt = 9u @@ -478,6 +1146,68 @@ class WiFiNetworkDiagnosticsCluster( return PacketUnicastRxCountAttribute(decodedValue) } + suspend fun subscribePacketUnicastRxCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PacketUnicastRxCountAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Packetunicastrxcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PacketUnicastRxCountAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PacketUnicastRxCountAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPacketUnicastTxCountAttribute(): PacketUnicastTxCountAttribute { val ATTRIBUTE_ID: UInt = 10u @@ -519,6 +1249,68 @@ class WiFiNetworkDiagnosticsCluster( return PacketUnicastTxCountAttribute(decodedValue) } + suspend fun subscribePacketUnicastTxCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + PacketUnicastTxCountAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Packetunicasttxcount attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUInt(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(PacketUnicastTxCountAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(PacketUnicastTxCountAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentMaxRateAttribute(): CurrentMaxRateAttribute { val ATTRIBUTE_ID: UInt = 11u @@ -560,6 +1352,68 @@ class WiFiNetworkDiagnosticsCluster( return CurrentMaxRateAttribute(decodedValue) } + suspend fun subscribeCurrentMaxRateAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentMaxRateAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentmaxrate attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentMaxRateAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentMaxRateAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOverrunCountAttribute(): OverrunCountAttribute { val ATTRIBUTE_ID: UInt = 12u @@ -601,6 +1455,66 @@ class WiFiNetworkDiagnosticsCluster( return OverrunCountAttribute(decodedValue) } + suspend fun subscribeOverrunCountAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + OverrunCountAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Overruncount attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: ULong? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getULong(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(OverrunCountAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(OverrunCountAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -639,6 +1553,65 @@ class WiFiNetworkDiagnosticsCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -677,6 +1650,65 @@ class WiFiNetworkDiagnosticsCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -715,6 +1747,63 @@ class WiFiNetworkDiagnosticsCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -753,6 +1842,63 @@ class WiFiNetworkDiagnosticsCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -784,6 +1930,56 @@ class WiFiNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -815,6 +2011,58 @@ class WiFiNetworkDiagnosticsCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(WiFiNetworkDiagnosticsCluster::class.java.name) const val CLUSTER_ID: UInt = 54u diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/WindowCoveringCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/WindowCoveringCluster.kt index ecb5a8ad407210..7fb2facd9cc45b 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/WindowCoveringCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/WindowCoveringCluster.kt @@ -20,11 +20,18 @@ package matter.controller.cluster.clusters import java.time.Duration import java.util.logging.Level import java.util.logging.Logger +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transform import matter.controller.InvokeRequest import matter.controller.InvokeResponse import matter.controller.MatterController import matter.controller.ReadData import matter.controller.ReadRequest +import matter.controller.SubscribeRequest +import matter.controller.SubscriptionState +import matter.controller.UByteSubscriptionState +import matter.controller.UIntSubscriptionState +import matter.controller.UShortSubscriptionState import matter.controller.WriteRequest import matter.controller.WriteRequests import matter.controller.WriteResponse @@ -42,28 +49,136 @@ class WindowCoveringCluster( ) { class CurrentPositionLiftAttribute(val value: UShort?) + sealed class CurrentPositionLiftAttributeSubscriptionState { + data class Success(val value: UShort?) : CurrentPositionLiftAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentPositionLiftAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentPositionLiftAttributeSubscriptionState() + } + class CurrentPositionTiltAttribute(val value: UShort?) + sealed class CurrentPositionTiltAttributeSubscriptionState { + data class Success(val value: UShort?) : CurrentPositionTiltAttributeSubscriptionState() + + data class Error(val exception: Exception) : CurrentPositionTiltAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentPositionTiltAttributeSubscriptionState() + } + class CurrentPositionLiftPercentageAttribute(val value: UByte?) + sealed class CurrentPositionLiftPercentageAttributeSubscriptionState { + data class Success(val value: UByte?) : + CurrentPositionLiftPercentageAttributeSubscriptionState() + + data class Error(val exception: Exception) : + CurrentPositionLiftPercentageAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentPositionLiftPercentageAttributeSubscriptionState() + } + class CurrentPositionTiltPercentageAttribute(val value: UByte?) + sealed class CurrentPositionTiltPercentageAttributeSubscriptionState { + data class Success(val value: UByte?) : + CurrentPositionTiltPercentageAttributeSubscriptionState() + + data class Error(val exception: Exception) : + CurrentPositionTiltPercentageAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentPositionTiltPercentageAttributeSubscriptionState() + } + class TargetPositionLiftPercent100thsAttribute(val value: UShort?) + sealed class TargetPositionLiftPercent100thsAttributeSubscriptionState { + data class Success(val value: UShort?) : + TargetPositionLiftPercent100thsAttributeSubscriptionState() + + data class Error(val exception: Exception) : + TargetPositionLiftPercent100thsAttributeSubscriptionState() + + object SubscriptionEstablished : TargetPositionLiftPercent100thsAttributeSubscriptionState() + } + class TargetPositionTiltPercent100thsAttribute(val value: UShort?) + sealed class TargetPositionTiltPercent100thsAttributeSubscriptionState { + data class Success(val value: UShort?) : + TargetPositionTiltPercent100thsAttributeSubscriptionState() + + data class Error(val exception: Exception) : + TargetPositionTiltPercent100thsAttributeSubscriptionState() + + object SubscriptionEstablished : TargetPositionTiltPercent100thsAttributeSubscriptionState() + } + class CurrentPositionLiftPercent100thsAttribute(val value: UShort?) + sealed class CurrentPositionLiftPercent100thsAttributeSubscriptionState { + data class Success(val value: UShort?) : + CurrentPositionLiftPercent100thsAttributeSubscriptionState() + + data class Error(val exception: Exception) : + CurrentPositionLiftPercent100thsAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentPositionLiftPercent100thsAttributeSubscriptionState() + } + class CurrentPositionTiltPercent100thsAttribute(val value: UShort?) + sealed class CurrentPositionTiltPercent100thsAttributeSubscriptionState { + data class Success(val value: UShort?) : + CurrentPositionTiltPercent100thsAttributeSubscriptionState() + + data class Error(val exception: Exception) : + CurrentPositionTiltPercent100thsAttributeSubscriptionState() + + object SubscriptionEstablished : CurrentPositionTiltPercent100thsAttributeSubscriptionState() + } + class GeneratedCommandListAttribute(val value: List) + sealed class GeneratedCommandListAttributeSubscriptionState { + data class Success(val value: List) : GeneratedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : GeneratedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : GeneratedCommandListAttributeSubscriptionState() + } + class AcceptedCommandListAttribute(val value: List) + sealed class AcceptedCommandListAttributeSubscriptionState { + data class Success(val value: List) : AcceptedCommandListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AcceptedCommandListAttributeSubscriptionState() + + object SubscriptionEstablished : AcceptedCommandListAttributeSubscriptionState() + } + class EventListAttribute(val value: List) + sealed class EventListAttributeSubscriptionState { + data class Success(val value: List) : EventListAttributeSubscriptionState() + + data class Error(val exception: Exception) : EventListAttributeSubscriptionState() + + object SubscriptionEstablished : EventListAttributeSubscriptionState() + } + class AttributeListAttribute(val value: List) + sealed class AttributeListAttributeSubscriptionState { + data class Success(val value: List) : AttributeListAttributeSubscriptionState() + + data class Error(val exception: Exception) : AttributeListAttributeSubscriptionState() + + object SubscriptionEstablished : AttributeListAttributeSubscriptionState() + } + suspend fun upOrOpen(timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u @@ -239,6 +354,56 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 0u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Type attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPhysicalClosedLimitLiftAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 1u @@ -275,6 +440,63 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribePhysicalClosedLimitLiftAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 1u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Physicalclosedlimitlift attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readPhysicalClosedLimitTiltAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 2u @@ -311,6 +533,63 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribePhysicalClosedLimitTiltAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 2u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Physicalclosedlimittilt attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPositionLiftAttribute(): CurrentPositionLiftAttribute { val ATTRIBUTE_ID: UInt = 3u @@ -352,6 +631,68 @@ class WindowCoveringCluster( return CurrentPositionLiftAttribute(decodedValue) } + suspend fun subscribeCurrentPositionLiftAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentPositionLiftAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentpositionlift attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentPositionLiftAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentPositionLiftAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPositionTiltAttribute(): CurrentPositionTiltAttribute { val ATTRIBUTE_ID: UInt = 4u @@ -393,6 +734,68 @@ class WindowCoveringCluster( return CurrentPositionTiltAttribute(decodedValue) } + suspend fun subscribeCurrentPositionTiltAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentPositionTiltAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentpositiontilt attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { emit(CurrentPositionTiltAttributeSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentPositionTiltAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfActuationsLiftAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 5u @@ -429,6 +832,63 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeNumberOfActuationsLiftAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 5u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofactuationslift attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readNumberOfActuationsTiltAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 6u @@ -465,6 +925,63 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeNumberOfActuationsTiltAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Numberofactuationstilt attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readConfigStatusAttribute(): UByte { val ATTRIBUTE_ID: UInt = 7u @@ -496,6 +1013,56 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeConfigStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Configstatus attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPositionLiftPercentageAttribute(): CurrentPositionLiftPercentageAttribute { val ATTRIBUTE_ID: UInt = 8u @@ -539,6 +1106,70 @@ class WindowCoveringCluster( return CurrentPositionLiftPercentageAttribute(decodedValue) } + suspend fun subscribeCurrentPositionLiftPercentageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 8u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentPositionLiftPercentageAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentpositionliftpercentage attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(CurrentPositionLiftPercentageAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentPositionLiftPercentageAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPositionTiltPercentageAttribute(): CurrentPositionTiltPercentageAttribute { val ATTRIBUTE_ID: UInt = 9u @@ -582,6 +1213,70 @@ class WindowCoveringCluster( return CurrentPositionTiltPercentageAttribute(decodedValue) } + suspend fun subscribeCurrentPositionTiltPercentageAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 9u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentPositionTiltPercentageAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentpositiontiltpercentage attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(CurrentPositionTiltPercentageAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentPositionTiltPercentageAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readOperationalStatusAttribute(): UByte { val ATTRIBUTE_ID: UInt = 10u @@ -613,6 +1308,58 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeOperationalStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 10u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Operationalstatus attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTargetPositionLiftPercent100thsAttribute(): TargetPositionLiftPercent100thsAttribute { val ATTRIBUTE_ID: UInt = 11u @@ -657,6 +1404,70 @@ class WindowCoveringCluster( return TargetPositionLiftPercent100thsAttribute(decodedValue) } + suspend fun subscribeTargetPositionLiftPercent100thsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 11u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TargetPositionLiftPercent100thsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Targetpositionliftpercent100ths attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(TargetPositionLiftPercent100thsAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(TargetPositionLiftPercent100thsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readTargetPositionTiltPercent100thsAttribute(): TargetPositionTiltPercent100thsAttribute { val ATTRIBUTE_ID: UInt = 12u @@ -701,6 +1512,70 @@ class WindowCoveringCluster( return TargetPositionTiltPercent100thsAttribute(decodedValue) } + suspend fun subscribeTargetPositionTiltPercent100thsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 12u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + TargetPositionTiltPercent100thsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Targetpositiontiltpercent100ths attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(TargetPositionTiltPercent100thsAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(TargetPositionTiltPercent100thsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEndProductTypeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 13u @@ -732,6 +1607,58 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeEndProductTypeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 13u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Endproducttype attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPositionLiftPercent100thsAttribute(): CurrentPositionLiftPercent100thsAttribute { val ATTRIBUTE_ID: UInt = 14u @@ -776,6 +1703,70 @@ class WindowCoveringCluster( return CurrentPositionLiftPercent100thsAttribute(decodedValue) } + suspend fun subscribeCurrentPositionLiftPercent100thsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 14u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentPositionLiftPercent100thsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentpositionliftpercent100ths attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(CurrentPositionLiftPercent100thsAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentPositionLiftPercent100thsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readCurrentPositionTiltPercent100thsAttribute(): CurrentPositionTiltPercent100thsAttribute { val ATTRIBUTE_ID: UInt = 15u @@ -820,6 +1811,70 @@ class WindowCoveringCluster( return CurrentPositionTiltPercent100thsAttribute(decodedValue) } + suspend fun subscribeCurrentPositionTiltPercent100thsAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 15u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + CurrentPositionTiltPercent100thsAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Currentpositiontiltpercent100ths attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + } else { + tlvReader.getNull(AnonymousTag) + null + } + + decodedValue?.let { + emit(CurrentPositionTiltPercent100thsAttributeSubscriptionState.Success(it)) + } + } + SubscriptionState.SubscriptionEstablished -> { + emit(CurrentPositionTiltPercent100thsAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInstalledOpenLimitLiftAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 16u @@ -856,6 +1911,63 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeInstalledOpenLimitLiftAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 16u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Installedopenlimitlift attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInstalledClosedLimitLiftAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 17u @@ -892,6 +2004,63 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeInstalledClosedLimitLiftAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 17u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Installedclosedlimitlift attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInstalledOpenLimitTiltAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 18u @@ -928,6 +2097,63 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeInstalledOpenLimitTiltAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 18u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Installedopenlimittilt attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readInstalledClosedLimitTiltAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 19u @@ -964,6 +2190,63 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeInstalledClosedLimitTiltAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 19u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Installedclosedlimittilt attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readModeAttribute(): UByte { val ATTRIBUTE_ID: UInt = 23u @@ -1035,6 +2318,56 @@ class WindowCoveringCluster( } } + suspend fun subscribeModeAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 23u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Mode attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte = tlvReader.getUByte(AnonymousTag) + + emit(UByteSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readSafetyStatusAttribute(): UShort? { val ATTRIBUTE_ID: UInt = 26u @@ -1071,6 +2404,61 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeSafetyStatusAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 26u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Safetystatus attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1109,6 +2497,65 @@ class WindowCoveringCluster( return GeneratedCommandListAttribute(decodedValue) } + suspend fun subscribeGeneratedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65528u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + GeneratedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Generatedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(GeneratedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(GeneratedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAcceptedCommandListAttribute(): AcceptedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65529u @@ -1147,6 +2594,65 @@ class WindowCoveringCluster( return AcceptedCommandListAttribute(decodedValue) } + suspend fun subscribeAcceptedCommandListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65529u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AcceptedCommandListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Acceptedcommandlist attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AcceptedCommandListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AcceptedCommandListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readEventListAttribute(): EventListAttribute { val ATTRIBUTE_ID: UInt = 65530u @@ -1185,6 +2691,63 @@ class WindowCoveringCluster( return EventListAttribute(decodedValue) } + suspend fun subscribeEventListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65530u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + EventListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Eventlist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(EventListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(EventListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readAttributeListAttribute(): AttributeListAttribute { val ATTRIBUTE_ID: UInt = 65531u @@ -1223,6 +2786,63 @@ class WindowCoveringCluster( return AttributeListAttribute(decodedValue) } + suspend fun subscribeAttributeListAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65531u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + AttributeListAttributeSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Attributelist attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) + } + tlvReader.exitContainer() + } + + emit(AttributeListAttributeSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(AttributeListAttributeSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readFeatureMapAttribute(): UInt { val ATTRIBUTE_ID: UInt = 65532u @@ -1254,6 +2874,56 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeFeatureMapAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65532u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UIntSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Featuremap attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UInt = tlvReader.getUInt(AnonymousTag) + + emit(UIntSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UIntSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readClusterRevisionAttribute(): UShort { val ATTRIBUTE_ID: UInt = 65533u @@ -1285,6 +2955,58 @@ class WindowCoveringCluster( return decodedValue } + suspend fun subscribeClusterRevisionAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 65533u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Clusterrevision attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort = tlvReader.getUShort(AnonymousTag) + + emit(UShortSubscriptionState.Success(decodedValue)) + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + companion object { private val logger = Logger.getLogger(WindowCoveringCluster::class.java.name) const val CLUSTER_ID: UInt = 258u diff --git a/src/controller/java/src/matter/controller/SubscriptionStates.kt b/src/controller/java/src/matter/controller/SubscriptionStates.kt new file mode 100644 index 00000000000000..a3ac27ff91b00f --- /dev/null +++ b/src/controller/java/src/matter/controller/SubscriptionStates.kt @@ -0,0 +1,130 @@ +/* + * 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 matter.controller + +sealed class BooleanSubscriptionState { + data class Success(val value: Boolean) : BooleanSubscriptionState() + + data class Error(val exception: Exception) : BooleanSubscriptionState() + + object SubscriptionEstablished : BooleanSubscriptionState() +} + +sealed class ByteSubscriptionState { + data class Success(val value: Byte) : ByteSubscriptionState() + + data class Error(val exception: Exception) : ByteSubscriptionState() + + object SubscriptionEstablished : ByteSubscriptionState() +} + +sealed class UByteSubscriptionState { + data class Success(val value: UByte) : UByteSubscriptionState() + + data class Error(val exception: Exception) : UByteSubscriptionState() + + object SubscriptionEstablished : UByteSubscriptionState() +} + +sealed class ShortSubscriptionState { + data class Success(val value: Short) : ShortSubscriptionState() + + data class Error(val exception: Exception) : ShortSubscriptionState() + + object SubscriptionEstablished : ShortSubscriptionState() +} + +sealed class UShortSubscriptionState { + data class Success(val value: UShort) : UShortSubscriptionState() + + data class Error(val exception: Exception) : UShortSubscriptionState() + + object SubscriptionEstablished : UShortSubscriptionState() +} + +sealed class IntSubscriptionState { + data class Success(val value: Int) : IntSubscriptionState() + + data class Error(val exception: Exception) : IntSubscriptionState() + + object SubscriptionEstablished : IntSubscriptionState() +} + +sealed class UIntSubscriptionState { + data class Success(val value: UInt) : UIntSubscriptionState() + + data class Error(val exception: Exception) : UIntSubscriptionState() + + object SubscriptionEstablished : UIntSubscriptionState() +} + +sealed class LongSubscriptionState { + data class Success(val value: Long) : LongSubscriptionState() + + data class Error(val exception: Exception) : LongSubscriptionState() + + object SubscriptionEstablished : LongSubscriptionState() +} + +sealed class ULongSubscriptionState { + data class Success(val value: ULong) : ULongSubscriptionState() + + data class Error(val exception: Exception) : ULongSubscriptionState() + + object SubscriptionEstablished : ULongSubscriptionState() +} + +sealed class FloatSubscriptionState { + data class Success(val value: Float) : FloatSubscriptionState() + + data class Error(val exception: Exception) : FloatSubscriptionState() + + object SubscriptionEstablished : FloatSubscriptionState() +} + +sealed class DoubleSubscriptionState { + data class Success(val value: Double) : DoubleSubscriptionState() + + data class Error(val exception: Exception) : DoubleSubscriptionState() + + object SubscriptionEstablished : DoubleSubscriptionState() +} + +sealed class CharSubscriptionState { + data class Success(val value: Char) : CharSubscriptionState() + + data class Error(val exception: Exception) : CharSubscriptionState() + + object SubscriptionEstablished : CharSubscriptionState() +} + +sealed class StringSubscriptionState { + data class Success(val value: String) : StringSubscriptionState() + + data class Error(val exception: Exception) : StringSubscriptionState() + + object SubscriptionEstablished : StringSubscriptionState() +} + +sealed class ByteArraySubscriptionState { + data class Success(val value: ByteArray) : ByteArraySubscriptionState() + + data class Error(val exception: Exception) : ByteArraySubscriptionState() + + object SubscriptionEstablished : ByteArraySubscriptionState() +} From d63ef5c873d482ed9b4afa878727e9ea7cf96003 Mon Sep 17 00:00:00 2001 From: jamesharrow <93921463+jamesharrow@users.noreply.github.com> Date: Mon, 18 Dec 2023 20:09:55 +0000 Subject: [PATCH 4/8] EVSE and Device Energy Management XML should use new base energy reporting types (and other minor fixes) (#30701) * Fix #30665 (EVSE) - Changed to use amperage_mA, energy_mWh - removed max on epoch_s - removed access for operate - removed side for events * Fix #30665 updates to try to get further with ZAP and autogen, but still fails with some parts of regen_all * Added ember-compatibility-functions.cpp which was missing. * Made all types all lowercase to resolve regen_all issues. * Fixed lint issue (trailing whitespace). * Aligned EVSE XML to same state as PR#30857 (includes SessionID being Nullable etc and in Fault Event). * Updated Device Energy Management XML to use power_mw, energy_mwh per spec definition. * Updated controller-clusters.zap * regen_all.py * Restyled by whitespace * Fixed types to be signed=true * Fixed 31032 - revert removal of side="server". * regen_all.py * Change to cause restyled to re-run after failure. :( * Revert "Change to cause restyled to re-run after failure. :(" This reverts commit b515c33e8186018c2f437a8d91a0cf80a028467e. --------- Co-authored-by: Restyled.io --- .../chip/device-energy-management-cluster.xml | 30 +++++++++---------- .../data_model/controller-clusters.matter | 30 +++++++++---------- .../zap-generated/attributes/Accessors.cpp | 4 +-- .../zap-generated/attributes/Accessors.h | 4 +-- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/app/zap-templates/zcl/data-model/chip/device-energy-management-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/device-energy-management-cluster.xml index 10e3af41e4a290..a07ac6d0d505e1 100644 --- a/src/app/zap-templates/zcl/data-model/chip/device-energy-management-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/device-energy-management-cluster.xml @@ -38,14 +38,14 @@ limitations under the License. ESAType ESACanGenerate ESAState - AbsMinPower - AbsMaxPower + AbsMinPower + AbsMaxPower PowerAdjustmentCapability Forecast - + Allows a client to request an adjustment in the power consumption of an ESA for a specified duration. @@ -79,7 +79,7 @@ limitations under the License. PowerAdjustEnd - + Paused @@ -138,8 +138,8 @@ limitations under the License. - - + + @@ -165,28 +165,28 @@ limitations under the License. - - - - + + + + - - + + - + - - + + \ No newline at end of file diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 5a622d7e1820bd..ef27bd2371d0c8 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -4451,13 +4451,13 @@ provisional cluster DeviceEnergyManagement = 152 { elapsed_s minPauseDuration = 6; elapsed_s maxPauseDuration = 7; optional int16u manufacturerESAState = 8; - optional int64s nominalPower = 9; - optional int64s minPower = 10; - optional int64s maxPower = 11; - optional int64s nominalEnergy = 12; + optional power_mw nominalPower = 9; + optional power_mw minPower = 10; + optional power_mw maxPower = 11; + optional energy_mwh nominalEnergy = 12; optional CostStruct costs[] = 13; - optional int64s minPowerAdjustment = 14; - optional int64s maxPowerAdjustment = 15; + optional power_mw minPowerAdjustment = 14; + optional power_mw maxPowerAdjustment = 15; optional elapsed_s minDurationAdjustment = 16; optional elapsed_s maxDurationAdjustment = 17; } @@ -4476,21 +4476,21 @@ provisional cluster DeviceEnergyManagement = 152 { struct ConstraintsStruct { epoch_s startTime = 0; elapsed_s duration = 1; - optional int64s nominalPower = 2; - optional int64s maximumEnergy = 3; + optional power_mw nominalPower = 2; + optional energy_mwh maximumEnergy = 3; optional int8s loadControl = 4; } struct PowerAdjustStruct { - int64s minPower = 0; - int64s maxPower = 1; + power_mw minPower = 0; + power_mw maxPower = 1; elapsed_s minDuration = 2; elapsed_s maxDuration = 3; } struct SlotAdjustmentStruct { int8u slotIndex = 0; - int64s nominalPower = 1; + power_mw nominalPower = 1; elapsed_s duration = 2; } @@ -4500,7 +4500,7 @@ provisional cluster DeviceEnergyManagement = 152 { info event PowerAdjustEnd = 1 { CauseEnum cause = 0; elapsed_s duration = 1; - int64s energyUse = 2; + energy_mwh energyUse = 2; } info event Paused = 2 { @@ -4512,8 +4512,8 @@ provisional cluster DeviceEnergyManagement = 152 { readonly attribute ESATypeEnum ESAType = 0; readonly attribute boolean ESACanGenerate = 1; readonly attribute ESAStateEnum ESAState = 2; - readonly attribute int64s absMinPower = 3; - readonly attribute int64s absMaxPower = 4; + readonly attribute power_mw absMinPower = 3; + readonly attribute power_mw absMaxPower = 4; readonly attribute optional nullable PowerAdjustStruct powerAdjustmentCapability[] = 5; readonly attribute optional nullable ForecastStruct forecast = 6; readonly attribute command_id generatedCommandList[] = 65528; @@ -4524,7 +4524,7 @@ provisional cluster DeviceEnergyManagement = 152 { readonly attribute int16u clusterRevision = 65533; request struct PowerAdjustRequestRequest { - int64s power = 0; + power_mw power = 0; elapsed_s duration = 1; } diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp index 18d8e98210b5e8..77c7512374fa94 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp @@ -10450,7 +10450,7 @@ EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_INT64S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_POWER_MW_ATTRIBUTE_TYPE); } } // namespace AbsMinPower @@ -10481,7 +10481,7 @@ EmberAfStatus Set(chip::EndpointId endpoint, int64_t value) Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_INT64S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::DeviceEnergyManagement::Id, Id, writable, ZCL_POWER_MW_ATTRIBUTE_TYPE); } } // namespace AbsMaxPower diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index 343be821fea273..2fdeaa1fdc71e7 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -2024,12 +2024,12 @@ EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::DeviceEnergyMa } // namespace ESAState namespace AbsMinPower { -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // int64s +EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // power_mw EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); } // namespace AbsMinPower namespace AbsMaxPower { -EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // int64s +EmberAfStatus Get(chip::EndpointId endpoint, int64_t * value); // power_mw EmberAfStatus Set(chip::EndpointId endpoint, int64_t value); } // namespace AbsMaxPower From 5786a35453f6c90ba7f4b74a9f722020ccc62140 Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Tue, 19 Dec 2023 13:41:57 +1300 Subject: [PATCH 5/8] Linux: Don't define CHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD by default (#31053) ... and compile out the related code if it is not defined. --- src/platform/Linux/ConnectivityManagerImpl.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/platform/Linux/ConnectivityManagerImpl.cpp b/src/platform/Linux/ConnectivityManagerImpl.cpp index 01d7a9668ff615..718824c6c428e5 100644 --- a/src/platform/Linux/ConnectivityManagerImpl.cpp +++ b/src/platform/Linux/ConnectivityManagerImpl.cpp @@ -63,10 +63,6 @@ #include #endif -#ifndef CHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD -#define CHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD "dhclient -nw %s" -#endif - using namespace ::chip; using namespace ::chip::TLV; using namespace ::chip::DeviceLayer; @@ -1139,6 +1135,10 @@ void ConnectivityManagerImpl::PostNetworkConnect() } } +#if defined(CHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD) + // CHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD can be defined to a command pattern + // to run once the network has been connected, with a %s placeholder for the + // interface name. E.g. "dhclient -nw %s" // Run dhclient for IP on WiFi. // TODO: The wifi can be managed by networkmanager on linux so we don't have to care about this. char cmdBuffer[128]; @@ -1152,6 +1152,7 @@ void ConnectivityManagerImpl::PostNetworkConnect() { ChipLogProgress(DeviceLayer, "dhclient is running on the %s interface.", sWiFiIfName); } +#endif // defined(CHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD) } CHIP_ERROR ConnectivityManagerImpl::CommitConfig() From 75113fc5876f1d7eb37e2a18eacb389c5ef94381 Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:14:25 +1300 Subject: [PATCH 6/8] ASN.1 null writer check should not bypass reading from TLVReader (#31088) ... since it is just intended to be an optimization. --- src/lib/asn1/ASN1Writer.cpp | 8 ++++---- src/lib/asn1/tests/TestASN1.cpp | 11 +++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/lib/asn1/ASN1Writer.cpp b/src/lib/asn1/ASN1Writer.cpp index 643d79038bca92..7d5a81f4cf1205 100644 --- a/src/lib/asn1/ASN1Writer.cpp +++ b/src/lib/asn1/ASN1Writer.cpp @@ -234,13 +234,13 @@ CHIP_ERROR ASN1Writer::PutBitString(uint8_t unusedBitCount, const uint8_t * enco CHIP_ERROR ASN1Writer::PutBitString(uint8_t unusedBitCount, chip::TLV::TLVReader & tlvReader) { - ReturnErrorCodeIf(IsNullWriter(), CHIP_NO_ERROR); - ByteSpan encodedBits; ReturnErrorOnFailure(tlvReader.Get(encodedBits)); VerifyOrReturnError(CanCastTo(encodedBits.size() + 1), ASN1_ERROR_LENGTH_OVERFLOW); + ReturnErrorCodeIf(IsNullWriter(), CHIP_NO_ERROR); + ReturnErrorOnFailure( EncodeHead(kASN1TagClass_Universal, kASN1UniversalTag_BitString, false, static_cast(encodedBits.size() + 1))); @@ -335,13 +335,13 @@ CHIP_ERROR ASN1Writer::PutValue(uint8_t cls, uint8_t tag, bool isConstructed, co CHIP_ERROR ASN1Writer::PutValue(uint8_t cls, uint8_t tag, bool isConstructed, chip::TLV::TLVReader & tlvReader) { - ReturnErrorCodeIf(IsNullWriter(), CHIP_NO_ERROR); - ByteSpan val; ReturnErrorOnFailure(tlvReader.Get(val)); VerifyOrReturnError(CanCastTo(val.size()), ASN1_ERROR_LENGTH_OVERFLOW); + ReturnErrorCodeIf(IsNullWriter(), CHIP_NO_ERROR); + ReturnErrorOnFailure(EncodeHead(cls, tag, isConstructed, static_cast(val.size()))); WriteData(val.data(), val.size()); diff --git a/src/lib/asn1/tests/TestASN1.cpp b/src/lib/asn1/tests/TestASN1.cpp index 6f4d5fe31d2d05..56899892abcc61 100644 --- a/src/lib/asn1/tests/TestASN1.cpp +++ b/src/lib/asn1/tests/TestASN1.cpp @@ -304,6 +304,17 @@ static void TestASN1_NullWriter(nlTestSuite * inSuite, void * inContext) encodedLen = writer.GetLengthWritten(); NL_TEST_ASSERT(inSuite, encodedLen == 0); + + // Methods that take a reader should still read from it, + // even if the output is suppressed by the null writer. + TLVReader emptyTlvReader; + emptyTlvReader.Init(ByteSpan()); + err = writer.PutBitString(0, emptyTlvReader); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_WRONG_TLV_TYPE); + + emptyTlvReader.Init(ByteSpan()); + err = writer.PutOctetString(kASN1TagClass_ContextSpecific, 123, emptyTlvReader); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_WRONG_TLV_TYPE); } static void TestASN1_ASN1UniversalTime(nlTestSuite * inSuite, void * inContext) From 9ba424238824f804e2fbfaa052249dfb1b2bc1bb Mon Sep 17 00:00:00 2001 From: Jaehoon-You <55170115+Jaehoon-You@users.noreply.github.com> Date: Tue, 19 Dec 2023 19:13:16 +0900 Subject: [PATCH 7/8] [Android] virtual-device-app: Remove collapsing layout (#30948) * virtual-device-app: Remove collapsing layout Signed-off-by: Jaehoon You Signed-off-by: Charles Kim * virtual-device-app: Cleanup resources Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --------- Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../common/src/main/res/values/themes.xml | 5 - .../device/app/core/ui/BaseFragment.kt | 11 - .../main/res/drawable/round_toggle_on_24.xml | 5 - .../ui/src/main/res/layout/layout_appbar.xml | 90 ++-- ...ace_bottom.xml => layout_bottom_space.xml} | 0 .../src/main/res/layout/layout_space_top.xml | 4 - .../ui/src/main/res/layout/layout_title.xml | 39 -- .../core/ui/src/main/res/values/dimens.xml | 9 - .../main/res/layout/fragment_door_lock.xml | 27 +- .../feature/control/OnOffSwitchFragment.kt | 5 +- .../res/layout/fragment_on_off_switch.xml | 59 +-- .../app/feature/main/LoadingFragment.kt | 11 - .../device/app/feature/main/MainFragment.kt | 11 - .../src/main/res/layout/fragment_loading.xml | 158 +++---- .../src/main/res/layout/fragment_main.xml | 112 ++--- .../app/feature/qrcode/QrcodeFragment.kt | 17 +- .../src/main/res/layout/fragment_qrcode.xml | 122 ++--- .../device/app/feature/setup/SetupFragment.kt | 11 - .../src/main/res/layout/fragment_setup.xml | 443 ++++++++---------- 19 files changed, 394 insertions(+), 745 deletions(-) delete mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_on_24.xml rename examples/virtual-device-app/android/App/core/ui/src/main/res/layout/{layout_space_bottom.xml => layout_bottom_space.xml} (100%) delete mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_top.xml delete mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_title.xml 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 index fcbe6bc78d57d4..a485b513217543 100644 --- 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 @@ -19,9 +19,4 @@ @color/color_background_secondary - \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseFragment.kt b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseFragment.kt index 9a254643c1c0a2..f4ebea90286ec3 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseFragment.kt +++ b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseFragment.kt @@ -15,7 +15,6 @@ import androidx.fragment.app.activityViewModels import com.matter.virtual.device.app.core.common.EventObserver import com.matter.virtual.device.app.core.common.MatterSettings import com.matter.virtual.device.app.core.ui.databinding.LayoutAppbarBinding -import kotlin.math.abs import timber.log.Timber abstract class BaseFragment( @@ -50,16 +49,6 @@ abstract class BaseFragment( (activity as AppCompatActivity).setSupportActionBar(layoutAppBarBinding.toolbar) (activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true) - layoutAppBarBinding.appBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset -> - var ratio = 0F - if (abs(verticalOffset) != 0) { - ratio = abs(verticalOffset).toFloat() / appBarLayout.totalScrollRange.toFloat() - } - - layoutAppBarBinding.collapseTitle.alpha = 1f - ratio * 2f + 0.1f - layoutAppBarBinding.toolbarTitle.alpha = (ratio - 0.5f) * 2f + 0.1f - } - layoutAppBarBinding.toolbarMoreMenuButton.setOnClickListener { Timber.d("More") showMoreMenuPopup(it) diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_on_24.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_on_24.xml deleted file mode 100644 index d42714cc7696e0..00000000000000 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_on_24.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_appbar.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_appbar.xml index b612ae66d543d2..26495c18b9f9e6 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_appbar.xml +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_appbar.xml @@ -5,75 +5,41 @@ + app:elevation="0dp"> - + android:layout_height="match_parent"> - + android:layout_height="match_parent"> - - - - - + android:layout_height="wrap_content" + android:textAlignment="viewStart" + android:textSize="@dimen/toolbar_title_text_size" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - - - - + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_bottom.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_bottom_space.xml similarity index 100% rename from examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_bottom.xml rename to examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_bottom_space.xml diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_top.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_top.xml deleted file mode 100644 index 47421036d7f28c..00000000000000 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_top.xml +++ /dev/null @@ -1,4 +0,0 @@ - - diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_title.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_title.xml deleted file mode 100644 index 7ad14914499681..00000000000000 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_title.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml index 24bd23b54f6de7..f1879112b94146 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml @@ -1,17 +1,8 @@ - 350dp - 25sp 17sp 20dp - 60dp - 60dp - 20dp - 10sp - 24sp - - 44dp 12dp 25dp 20dp diff --git a/examples/virtual-device-app/android/App/feature/closure/src/main/res/layout/fragment_door_lock.xml b/examples/virtual-device-app/android/App/feature/closure/src/main/res/layout/fragment_door_lock.xml index 9caa1a2b67a48b..5c4807cbff7ef4 100644 --- a/examples/virtual-device-app/android/App/feature/closure/src/main/res/layout/fragment_door_lock.xml +++ b/examples/virtual-device-app/android/App/feature/closure/src/main/res/layout/fragment_door_lock.xml @@ -21,27 +21,20 @@ android:layout_height="wrap_content" android:orientation="vertical"> - + - + - - - - + - + diff --git a/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchFragment.kt b/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchFragment.kt index 3b13eb0898e123..f5142bf0da3242 100644 --- a/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchFragment.kt +++ b/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchFragment.kt @@ -27,11 +27,8 @@ class OnOffSwitchFragment : override fun setupAppbar(): LayoutAppbarBinding = binding.appbar override fun setupUi() { - /** title icon */ - binding.onOffSwitchTitleLayout.titleIcon.setImageResource(matterSettings.device.deviceIconResId) - /** title text */ - binding.onOffSwitchTitleLayout.titleText.text = getString(matterSettings.device.deviceNameResId) + binding.appbar.toolbarTitle.text = getString(matterSettings.device.deviceNameResId) /** OnOff layout */ binding.onOffSwitchOnOffLayout.buttonData = diff --git a/examples/virtual-device-app/android/App/feature/control/src/main/res/layout/fragment_on_off_switch.xml b/examples/virtual-device-app/android/App/feature/control/src/main/res/layout/fragment_on_off_switch.xml index 1978e7c383f3d0..0635a23c87c9f2 100644 --- a/examples/virtual-device-app/android/App/feature/control/src/main/res/layout/fragment_on_off_switch.xml +++ b/examples/virtual-device-app/android/App/feature/control/src/main/res/layout/fragment_on_off_switch.xml @@ -1,11 +1,9 @@ - + - + android:layout_height="match_parent"> - + android:layout_marginTop="?attr/actionBarSize"> - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="wrap_content" + android:orientation="vertical"> + + + + + + + + + \ 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/LoadingFragment.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingFragment.kt index e5d768c3e790b7..244b3b668cf874 100644 --- a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingFragment.kt +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingFragment.kt @@ -20,7 +20,6 @@ import com.matter.virtual.device.app.core.common.MatterSettings import com.matter.virtual.device.app.core.ui.SharedViewModel import com.matter.virtual.device.app.feature.main.databinding.FragmentLoadingBinding import dagger.hilt.android.AndroidEntryPoint -import kotlin.math.abs import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString @@ -57,16 +56,6 @@ class LoadingFragment : Fragment() { (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: LoadingFragmentArgs by navArgs() this.matterSettings = Json.decodeFromString(args.setting) 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 index 861bf01b257817..0365727b110d25 100644 --- 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 @@ -20,7 +20,6 @@ import com.matter.virtual.device.app.core.ui.SharedViewModel 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 @@ -55,16 +54,6 @@ class MainFragment : Fragment() { (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 - } - viewModel.uiState.observe(viewLifecycleOwner) { uiState -> Timber.d("uiState:$uiState") when (uiState) { diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_loading.xml b/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_loading.xml index a76061ed6ca8e4..0a16475314f70b 100644 --- a/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_loading.xml +++ b/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_loading.xml @@ -2,7 +2,7 @@ - @@ -10,121 +10,81 @@ + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - + android:layout_height="match_parent"> - - - + android:layout_height="match_parent"> - - - - - - + android:layout_height="wrap_content" + android:text="@string/title_loading" + android:textAlignment="viewStart" + android:textSize="@dimen/toolbar_title_text_size" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + - + android:layout_marginTop="?attr/actionBarSize" + android:orientation="vertical"> - + android:layout_marginStart="@dimen/menu_item_side_space" + android:layout_marginTop="20dp" + android:layout_marginEnd="@dimen/menu_item_side_space" + android:background="@drawable/menu_item_bg"> - + android:layout_marginEnd="20dp" + android:layout_marginBottom="20dp" + android:indeterminate="true" + app:indicatorColor="@color/colorControlActivated" + app:layout_constraintBottom_toTopOf="@+id/loading_description" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - - - - - - - + + + + \ No newline at end of file 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 index 724e9f21634261..2bbe9df759b809 100644 --- 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 @@ -2,103 +2,59 @@ - - - - - + android:layout_height="match_parent"> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - - - + android:layout_height="?attr/actionBarSize"> - + android:layout_height="match_parent"> - - - - - - + android:layout_height="wrap_content" + android:text="@string/title_main" + android:textAlignment="viewStart" + android:textSize="@dimen/toolbar_title_text_size" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + - + android:layout_marginTop="?attr/actionBarSize"> - - - - - - + android:orientation="vertical" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + 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 index 6f220d7851453b..a6ea23ede767e6 100644 --- 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 @@ -14,11 +14,14 @@ import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import com.matter.virtual.device.app.core.common.* +import com.matter.virtual.device.app.core.common.DeepLink +import com.matter.virtual.device.app.core.common.EventObserver +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.core.ui.SharedViewModel 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.encodeToString @@ -55,16 +58,6 @@ class QrcodeFragment : Fragment() { (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) 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 index 5bd72ce74776d5..0d141c97ed6836 100644 --- 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 @@ -9,86 +9,52 @@ type="com.matter.virtual.device.app.feature.qrcode.QrcodeViewModel" /> - + android:layout_height="match_parent"> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - - - + android:layout_height="match_parent"> - + android:layout_height="match_parent"> - - - - - - + android:layout_height="wrap_content" + android:text="@string/title_qrcode" + android:textAlignment="viewStart" + android:textSize="@dimen/toolbar_title_text_size" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + - + android:layout_marginTop="?attr/actionBarSize"> - + android:layout_height="match_parent" + android:orientation="vertical"> @@ -124,7 +89,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginVertical="@dimen/menu_item_text_margin_vertical" - android:layout_marginStart="@dimen/menu_item_image_margin_start" android:layout_marginEnd="@dimen/menu_item_text_margin_end" android:ellipsize="end" android:singleLine="true" @@ -235,24 +199,18 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/setup_pin_code_text" /> - - - - - - - + + + + + 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 index 79ede035a2f506..adf4c869833acb 100644 --- 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 @@ -20,7 +20,6 @@ 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 @@ -57,16 +56,6 @@ class SetupFragment : Fragment() { (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) 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 index 7bf2118df30ac5..c76a55d3f9dfde 100644 --- 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 @@ -2,290 +2,243 @@ - - - - - + android:layout_height="match_parent"> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - - - + android:layout_height="?attr/actionBarSize"> - + android:layout_height="match_parent"> - - - - - - + android:layout_height="wrap_content" + android:text="@string/title_setup" + android:textAlignment="viewStart" + android:textSize="@dimen/toolbar_title_text_size" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + - + android:layout_marginTop="?attr/actionBarSize" + android:orientation="vertical"> - + android:layout_height="wrap_content" + android:layout_marginHorizontal="12dp" + android:background="@drawable/menu_item_bg" + android:gravity="center_vertical" + android:paddingStart="20dp" + android:paddingTop="12dp" + android:paddingEnd="20dp" + android:paddingBottom="12dp"> - + + + android:textAlignment="viewStart" + android:textSize="@dimen/device_item_value_text_size" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/setup_device_name_text" /> - + - + - - + - + + + + + + + - - - - - - - - + + - - - - - - - - - - - - - + + - - - - + android:layout_weight="1" + android:buttonTint="@color/textColor" + android:text="@string/wifi_ble" + android:textSize="@dimen/device_item_value_text_small_size" /> - + + - + + + + + + + + + - + - - - - - + + + - - + android:text="@string/save" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + From e49c56da5b73d5e0f8a9fc3580762b59cbc83092 Mon Sep 17 00:00:00 2001 From: fesseha-eve <88329315+fessehaeve@users.noreply.github.com> Date: Tue, 19 Dec 2023 11:48:43 +0100 Subject: [PATCH 8/8] Update boolean configuration cluster XML according to latest spec (#30950) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update boolean configuration cluster according to latest spec * rename to boolean state configuration cluster * regen after rename to boolean state configuration * update device type and cluster names * fixed typo Co-authored-by: René Josefsen <69624991+ReneJosefsen@users.noreply.github.com> * fixed typo, regenerate zap, added Rain Sensor device type * update missed cluster names after renaming * rename and restyle * update domain to Gereral as per https://github.com/CHIP-Specifications/connectedhomeip-spec/pull/8686 --------- Co-authored-by: René Josefsen <69624991+ReneJosefsen@users.noreply.github.com> --- docs/clusters.md | 2 +- src/app/util/util.cpp | 2 +- src/app/zap-templates/zcl/data-model/all.xml | 2 +- ...> boolean-state-configuration-cluster.xml} | 38 +- .../zcl/data-model/chip/matter-devices.xml | 31 +- .../zcl/zcl-with-test-extensions.json | 2 +- src/app/zap-templates/zcl/zcl.json | 2 +- src/app/zap_cluster_list.json | 4 +- .../data_model/controller-clusters.matter | 37 +- .../chip/devicecontroller/ChipClusters.java | 169 +++- .../devicecontroller/ChipEventStructs.java | 56 +- .../devicecontroller/ClusterIDMapping.java | 46 +- .../devicecontroller/ClusterInfoMapping.java | 53 +- .../devicecontroller/ClusterReadMapping.java | 164 ++-- .../devicecontroller/ClusterWriteMapping.java | 42 +- ...gurationClusterAlarmsStateChangedEvent.kt} | 11 +- ...ateConfigurationClusterSensorFaultEvent.kt | 55 ++ .../chip/devicecontroller/cluster/files.gni | 3 +- ...kt => BooleanStateConfigurationCluster.kt} | 447 ++++++++- ...gurationClusterAlarmsStateChangedEvent.kt} | 11 +- ...ateConfigurationClusterSensorFaultEvent.kt | 55 ++ .../java/matter/controller/cluster/files.gni | 5 +- .../CHIPAttributeTLVValueDecoder.cpp | 72 +- .../java/zap-generated/CHIPClientCallbacks.h | 8 +- .../zap-generated/CHIPClustersWrite-JNI.cpp | 60 +- .../CHIPEventTLVValueDecoder.cpp | 30 +- .../java/zap-generated/CHIPReadCallbacks.cpp | 56 +- .../chip/devicecontroller/ChipClusters.java | 5 +- .../python/chip/clusters/CHIPClusters.py | 50 +- .../python/chip/clusters/Objects.py | 131 ++- .../python/chip/clusters/__init__.py | 4 +- .../CHIP/templates/availability.yaml | 2 +- .../MTRAttributeSpecifiedCheck.mm | 22 +- .../MTRAttributeTLVValueDecoder.mm | 58 +- .../CHIP/zap-generated/MTRBaseClusters.h | 80 +- .../CHIP/zap-generated/MTRBaseClusters.mm | 276 ++++-- .../CHIP/zap-generated/MTRClusterConstants.h | 39 +- .../CHIP/zap-generated/MTRClusters.h | 25 +- .../CHIP/zap-generated/MTRClusters.mm | 86 +- .../zap-generated/MTRCommandPayloadsObjc.h | 32 +- .../zap-generated/MTRCommandPayloadsObjc.mm | 87 +- .../MTRCommandPayloads_Internal.h | 8 +- .../zap-generated/MTRCommandTimedCheck.mm | 8 +- .../zap-generated/MTRDeviceTypeMetadata.mm | 3 +- .../zap-generated/MTREventTLVValueDecoder.mm | 18 +- .../CHIP/zap-generated/MTRStructsObjc.h | 5 +- .../CHIP/zap-generated/MTRStructsObjc.mm | 14 +- src/python_testing/TC_BSENCFG_2_1.py | 6 +- .../zap-generated/attributes/Accessors.cpp | 192 +++- .../zap-generated/attributes/Accessors.h | 48 +- .../app-common/zap-generated/callback.h | 50 +- .../zap-generated/cluster-enums-check.h | 14 - .../app-common/zap-generated/cluster-enums.h | 23 +- .../zap-generated/cluster-objects.cpp | 70 +- .../zap-generated/cluster-objects.h | 185 +++- .../app-common/zap-generated/ids/Attributes.h | 30 +- .../app-common/zap-generated/ids/Clusters.h | 4 +- .../app-common/zap-generated/ids/Commands.h | 12 +- .../app-common/zap-generated/ids/Events.h | 4 +- .../app-common/zap-generated/print-cluster.h | 10 +- .../zap-generated/cluster/Commands.h | 153 +++- .../cluster/logging/DataModelLogger.cpp | 74 +- .../cluster/logging/DataModelLogger.h | 7 +- .../zap-generated/cluster/Commands.h | 859 +++++++++++++----- 64 files changed, 3083 insertions(+), 1074 deletions(-) rename src/app/zap-templates/zcl/data-model/chip/{boolean-sensor-configuration-cluster.xml => boolean-state-configuration-cluster.xml} (54%) rename src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/{BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt => BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt} (86%) create mode 100644 src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt rename src/controller/java/generated/java/matter/controller/cluster/clusters/{BooleanSensorConfigurationCluster.kt => BooleanStateConfigurationCluster.kt} (72%) rename src/controller/java/generated/java/matter/controller/cluster/eventstructs/{BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt => BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt} (86%) create mode 100644 src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt diff --git a/docs/clusters.md b/docs/clusters.md index 8d1d29a84d2e87..2043c6fe45ffb9 100644 --- a/docs/clusters.md +++ b/docs/clusters.md @@ -75,7 +75,7 @@ Generally regenerate using one of: | 97 | 0x61 | RvcOperationalState | | 113 | 0x71 | HepaFilterMonitoring | | 114 | 0x72 | ActivatedCarbonFilterMonitoring | -| 128 | 0x80 | BooleanSensorConfiguration | +| 128 | 0x80 | BooleanStateConfiguration | | 129 | 0x81 | ValveConfigurationAndControl | | 145 | 0x91 | ElectricalEnergyMeasurement | | 150 | 0x96 | DemandResponseLoadControl | diff --git a/src/app/util/util.cpp b/src/app/util/util.cpp index 9d618dcc69e93c..8c4f088f118554 100644 --- a/src/app/util/util.cpp +++ b/src/app/util/util.cpp @@ -158,7 +158,7 @@ void MatterRefrigeratorAndTemperatureControlledCabinetModePluginServerInitCallba void MatterOperationalStatePluginServerInitCallback() {} void MatterRvcOperationalStatePluginServerInitCallback() {} void MatterDishwasherAlarmPluginServerInitCallback() {} -void MatterBooleanSensorConfigurationPluginServerInitCallback() {} +void MatterBooleanStateConfigurationPluginServerInitCallback() {} void MatterValveConfigurationAndControlPluginServerInitCallback() {} void MatterMicrowaveOvenModePluginServerInitCallback() {} // **************************************** diff --git a/src/app/zap-templates/zcl/data-model/all.xml b/src/app/zap-templates/zcl/data-model/all.xml index 3556c0309206e7..4eedb32f3578d9 100644 --- a/src/app/zap-templates/zcl/data-model/all.xml +++ b/src/app/zap-templates/zcl/data-model/all.xml @@ -10,8 +10,8 @@ - + diff --git a/src/app/zap-templates/zcl/data-model/chip/boolean-sensor-configuration-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/boolean-state-configuration-cluster.xml similarity index 54% rename from src/app/zap-templates/zcl/data-model/chip/boolean-sensor-configuration-cluster.xml rename to src/app/zap-templates/zcl/data-model/chip/boolean-state-configuration-cluster.xml index 44bb181f2b9d59..2b5f81eed744e1 100644 --- a/src/app/zap-templates/zcl/data-model/chip/boolean-sensor-configuration-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/boolean-state-configuration-cluster.xml @@ -31,33 +31,40 @@ limitations under the License. - + - - - - + + - Boolean Sensor Configuration - Measurement & Sensing + General + Boolean State Configuration 0x0080 - BOOLEAN_SENSOR_CONFIGURATION_CLUSTER + BOOLEAN_STATE_CONFIGURATION_CLUSTER true true This cluster is used to configure a boolean sensor. - SensitivityLevel - AlarmsActive - AlarmsSuppressed - AlarmsEnabled + CurrentSensitivityLevel + SupportedSensitivityLevels + DefaultSensitivityLevel + AlarmsActive + AlarmsSuppressed + AlarmsEnabled + AlarmsSupported + SensorFault - - This command is used to suppress the specified alarm. + + This command is used to suppress the specified alarm mode. + + This command is used to enable or disable the specified alarm mode. + + + This event SHALL be generated when any bits in the AlarmsActive and/or AlarmsSuppressed attributes change. @@ -65,7 +72,8 @@ limitations under the License. - This event SHALL be generated when the device detects a sensor fault. + This event SHALL be generated when the device registers or clears a fault. + diff --git a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml index fdbab080f32854..58bba4c850f9a6 100644 --- a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml +++ b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml @@ -2100,9 +2100,9 @@ limitations under the License. - MA-boolean-sensor + MA-water-freeze-detector CHIP - Matter Boolean Sensor + Matter Water Freeze Detector 0x0103 0x0041 Simple @@ -2110,9 +2110,8 @@ limitations under the License. - - TAG_LIST - + + @@ -2137,14 +2136,26 @@ limitations under the License. 0x0043 Simple Endpoint - Matter Boolean Sensor - - - TAG_LIST - + + + + + + MA-rain-sensor + CHIP + Matter Rain Sensor + 0x0103 + 0x0044 + Simple + Endpoint + + + + + diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index 3a59d976945f68..31a334577fb4eb 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -24,8 +24,8 @@ "barrier-control-cluster.xml", "basic-information-cluster.xml", "binding-cluster.xml", - "boolean-sensor-configuration-cluster.xml", "boolean-state-cluster.xml", + "boolean-state-configuration-cluster.xml", "actions-cluster.xml", "bridged-device-basic-information.xml", "chip-ota.xml", diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index 7913f6a850c18f..565d500aeb2293 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -23,8 +23,8 @@ "barrier-control-cluster.xml", "basic-information-cluster.xml", "binding-cluster.xml", - "boolean-sensor-configuration-cluster.xml", "boolean-state-cluster.xml", + "boolean-state-configuration-cluster.xml", "actions-cluster.xml", "bridged-device-basic-information.xml", "chip-ota.xml", diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index cdd92f9698b1e8..77b466541f1a54 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -15,8 +15,8 @@ "BASIC_INFORMATION_CLUSTER": [], "BINARY_INPUT_BASIC_CLUSTER": [], "BINDING_CLUSTER": [], - "BOOLEAN_SENSOR_CONFIGURATION_CLUSTER": [], "BOOLEAN_STATE_CLUSTER": [], + "BOOLEAN_STATE_CONFIGURATION_CLUSTER": [], "BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER": [], "CARBON_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER": [], "CARBON_MONOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER": [], @@ -146,8 +146,8 @@ "BASIC_INFORMATION_CLUSTER": ["basic-information"], "BINARY_INPUT_BASIC_CLUSTER": [], "BINDING_CLUSTER": ["bindings"], - "BOOLEAN_SENSOR_CONFIGURATION_CLUSTER": [], "BOOLEAN_STATE_CLUSTER": [], + "BOOLEAN_STATE_CONFIGURATION_CLUSTER": [], "BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER": [ "bridged-device-basic-information-server" ], diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index ef27bd2371d0c8..f2edd0f158926a 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -3997,15 +3997,9 @@ cluster ActivatedCarbonFilterMonitoring = 114 { } /** This cluster is used to configure a boolean sensor. */ -provisional cluster BooleanSensorConfiguration = 128 { +provisional cluster BooleanStateConfiguration = 128 { revision 1; - enum SensitivityEnum : enum8 { - kHigh = 0; - kStandard = 1; - kLow = 2; - } - bitmap AlarmModeBitmap : bitmap8 { kVisual = 0x1; kAudible = 0x2; @@ -4018,18 +4012,27 @@ provisional cluster BooleanSensorConfiguration = 128 { kSensitivityLevel = 0x8; } + bitmap SensorFaultBitmap : bitmap16 { + kGeneralFault = 0x1; + } + info event AlarmsStateChanged = 0 { AlarmModeBitmap alarmsActive = 0; optional AlarmModeBitmap alarmsSuppressed = 1; } info event SensorFault = 1 { + SensorFaultBitmap sensorFault = 0; } - attribute optional SensitivityEnum sensitivityLevel = 0; - readonly attribute optional AlarmModeBitmap alarmsActive = 1; - readonly attribute optional AlarmModeBitmap alarmsSuppressed = 2; - attribute optional AlarmModeBitmap alarmsEnabled = 3; + attribute optional int8u currentSensitivityLevel = 0; + readonly attribute optional int8u supportedSensitivityLevels = 1; + readonly attribute optional int8u defaultSensitivityLevel = 2; + readonly attribute optional AlarmModeBitmap alarmsActive = 3; + readonly attribute optional AlarmModeBitmap alarmsSuppressed = 4; + readonly attribute optional AlarmModeBitmap alarmsEnabled = 5; + readonly attribute optional AlarmModeBitmap alarmsSupported = 6; + readonly attribute optional SensorFaultBitmap sensorFault = 7; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -4037,12 +4040,18 @@ provisional cluster BooleanSensorConfiguration = 128 { readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; - request struct SuppressRequestRequest { + request struct SuppressAlarmRequest { AlarmModeBitmap alarmsToSuppress = 0; } - /** This command is used to suppress the specified alarm. */ - command SuppressRequest(SuppressRequestRequest): DefaultSuccess = 0; + request struct EnableDisableAlarmRequest { + AlarmModeBitmap alarmsToEnableDisable = 0; + } + + /** This command is used to suppress the specified alarm mode. */ + command SuppressAlarm(SuppressAlarmRequest): DefaultSuccess = 0; + /** This command is used to enable or disable the specified alarm mode. */ + command EnableDisableAlarm(EnableDisableAlarmRequest): DefaultSuccess = 1; } /** This cluster is used to configure a valve. */ diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index d4a978192119d9..601c14f5da66c2 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -27416,13 +27416,17 @@ public void onSuccess(byte[] tlv) { } } - public static class BooleanSensorConfigurationCluster extends BaseChipCluster { + public static class BooleanStateConfigurationCluster extends BaseChipCluster { public static final long CLUSTER_ID = 128L; - private static final long SENSITIVITY_LEVEL_ATTRIBUTE_ID = 0L; - private static final long ALARMS_ACTIVE_ATTRIBUTE_ID = 1L; - private static final long ALARMS_SUPPRESSED_ATTRIBUTE_ID = 2L; - private static final long ALARMS_ENABLED_ATTRIBUTE_ID = 3L; + private static final long CURRENT_SENSITIVITY_LEVEL_ATTRIBUTE_ID = 0L; + private static final long SUPPORTED_SENSITIVITY_LEVELS_ATTRIBUTE_ID = 1L; + private static final long DEFAULT_SENSITIVITY_LEVEL_ATTRIBUTE_ID = 2L; + private static final long ALARMS_ACTIVE_ATTRIBUTE_ID = 3L; + private static final long ALARMS_SUPPRESSED_ATTRIBUTE_ID = 4L; + private static final long ALARMS_ENABLED_ATTRIBUTE_ID = 5L; + private static final long ALARMS_SUPPORTED_ATTRIBUTE_ID = 6L; + private static final long SENSOR_FAULT_ATTRIBUTE_ID = 7L; private static final long GENERATED_COMMAND_LIST_ATTRIBUTE_ID = 65528L; private static final long ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID = 65529L; private static final long EVENT_LIST_ATTRIBUTE_ID = 65530L; @@ -27430,7 +27434,7 @@ public static class BooleanSensorConfigurationCluster extends BaseChipCluster { private static final long FEATURE_MAP_ATTRIBUTE_ID = 65532L; private static final long CLUSTER_REVISION_ATTRIBUTE_ID = 65533L; - public BooleanSensorConfigurationCluster(long devicePtr, int endpointId) { + public BooleanStateConfigurationCluster(long devicePtr, int endpointId) { super(devicePtr, endpointId, CLUSTER_ID); } @@ -27440,11 +27444,11 @@ public long initWithDevice(long devicePtr, int endpointId) { return 0L; } - public void suppressRequest(DefaultClusterCallback callback, Integer alarmsToSuppress) { - suppressRequest(callback, alarmsToSuppress, 0); + public void suppressAlarm(DefaultClusterCallback callback, Integer alarmsToSuppress) { + suppressAlarm(callback, alarmsToSuppress, 0); } - public void suppressRequest(DefaultClusterCallback callback, Integer alarmsToSuppress, int timedInvokeTimeoutMs) { + public void suppressAlarm(DefaultClusterCallback callback, Integer alarmsToSuppress, int timedInvokeTimeoutMs) { final long commandId = 0L; ArrayList elements = new ArrayList<>(); @@ -27460,6 +27464,26 @@ public void onResponse(StructType invokeStructValue) { }}, commandId, value, timedInvokeTimeoutMs); } + public void enableDisableAlarm(DefaultClusterCallback callback, Integer alarmsToEnableDisable) { + enableDisableAlarm(callback, alarmsToEnableDisable, 0); + } + + public void enableDisableAlarm(DefaultClusterCallback callback, Integer alarmsToEnableDisable, int timedInvokeTimeoutMs) { + final long commandId = 1L; + + ArrayList elements = new ArrayList<>(); + final long alarmsToEnableDisableFieldID = 0L; + BaseTLVType alarmsToEnableDisabletlvValue = new UIntType(alarmsToEnableDisable); + elements.add(new StructElement(alarmsToEnableDisableFieldID, alarmsToEnableDisabletlvValue)); + + StructType value = new StructType(elements); + invoke(new InvokeCallbackImpl(callback) { + @Override + public void onResponse(StructType invokeStructValue) { + callback.onSuccess(); + }}, commandId, value, timedInvokeTimeoutMs); + } + public interface GeneratedCommandListAttributeCallback extends BaseAttributeCallback { void onSuccess(List value); } @@ -27476,9 +27500,9 @@ public interface AttributeListAttributeCallback extends BaseAttributeCallback { void onSuccess(List value); } - public void readSensitivityLevelAttribute( + public void readCurrentSensitivityLevelAttribute( IntegerAttributeCallback callback) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SENSITIVITY_LEVEL_ATTRIBUTE_ID); + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CURRENT_SENSITIVITY_LEVEL_ATTRIBUTE_ID); readAttribute(new ReportCallbackImpl(callback, path) { @Override @@ -27486,28 +27510,78 @@ public void onSuccess(byte[] tlv) { Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } - }, SENSITIVITY_LEVEL_ATTRIBUTE_ID, true); + }, CURRENT_SENSITIVITY_LEVEL_ATTRIBUTE_ID, true); } - public void writeSensitivityLevelAttribute(DefaultClusterCallback callback, Integer value) { - writeSensitivityLevelAttribute(callback, value, 0); + public void writeCurrentSensitivityLevelAttribute(DefaultClusterCallback callback, Integer value) { + writeCurrentSensitivityLevelAttribute(callback, value, 0); } - public void writeSensitivityLevelAttribute(DefaultClusterCallback callback, Integer value, int timedWriteTimeoutMs) { + public void writeCurrentSensitivityLevelAttribute(DefaultClusterCallback callback, Integer value, int timedWriteTimeoutMs) { BaseTLVType tlvValue = new UIntType(value); - writeAttribute(new WriteAttributesCallbackImpl(callback), SENSITIVITY_LEVEL_ATTRIBUTE_ID, tlvValue, timedWriteTimeoutMs); + writeAttribute(new WriteAttributesCallbackImpl(callback), CURRENT_SENSITIVITY_LEVEL_ATTRIBUTE_ID, tlvValue, timedWriteTimeoutMs); } - public void subscribeSensitivityLevelAttribute( + public void subscribeCurrentSensitivityLevelAttribute( IntegerAttributeCallback callback, int minInterval, int maxInterval) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SENSITIVITY_LEVEL_ATTRIBUTE_ID); + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CURRENT_SENSITIVITY_LEVEL_ATTRIBUTE_ID); subscribeAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); } - }, SENSITIVITY_LEVEL_ATTRIBUTE_ID, minInterval, maxInterval); + }, CURRENT_SENSITIVITY_LEVEL_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readSupportedSensitivityLevelsAttribute( + IntegerAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SUPPORTED_SENSITIVITY_LEVELS_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, SUPPORTED_SENSITIVITY_LEVELS_ATTRIBUTE_ID, true); + } + + public void subscribeSupportedSensitivityLevelsAttribute( + IntegerAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SUPPORTED_SENSITIVITY_LEVELS_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + } + }, SUPPORTED_SENSITIVITY_LEVELS_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readDefaultSensitivityLevelAttribute( + IntegerAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, DEFAULT_SENSITIVITY_LEVEL_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, DEFAULT_SENSITIVITY_LEVEL_ATTRIBUTE_ID, true); + } + + public void subscribeDefaultSensitivityLevelAttribute( + IntegerAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, DEFAULT_SENSITIVITY_LEVEL_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + } + }, DEFAULT_SENSITIVITY_LEVEL_ATTRIBUTE_ID, minInterval, maxInterval); } public void readAlarmsActiveAttribute( @@ -27573,25 +27647,66 @@ public void onSuccess(byte[] tlv) { }, ALARMS_ENABLED_ATTRIBUTE_ID, true); } - public void writeAlarmsEnabledAttribute(DefaultClusterCallback callback, Integer value) { - writeAlarmsEnabledAttribute(callback, value, 0); + public void subscribeAlarmsEnabledAttribute( + IntegerAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ALARMS_ENABLED_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + } + }, ALARMS_ENABLED_ATTRIBUTE_ID, minInterval, maxInterval); } - public void writeAlarmsEnabledAttribute(DefaultClusterCallback callback, Integer value, int timedWriteTimeoutMs) { - BaseTLVType tlvValue = new UIntType(value); - writeAttribute(new WriteAttributesCallbackImpl(callback), ALARMS_ENABLED_ATTRIBUTE_ID, tlvValue, timedWriteTimeoutMs); + public void readAlarmsSupportedAttribute( + IntegerAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ALARMS_SUPPORTED_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, ALARMS_SUPPORTED_ATTRIBUTE_ID, true); } - public void subscribeAlarmsEnabledAttribute( + public void subscribeAlarmsSupportedAttribute( IntegerAttributeCallback callback, int minInterval, int maxInterval) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ALARMS_ENABLED_ATTRIBUTE_ID); + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, ALARMS_SUPPORTED_ATTRIBUTE_ID); subscribeAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); } - }, ALARMS_ENABLED_ATTRIBUTE_ID, minInterval, maxInterval); + }, ALARMS_SUPPORTED_ATTRIBUTE_ID, minInterval, maxInterval); + } + + public void readSensorFaultAttribute( + IntegerAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SENSOR_FAULT_ATTRIBUTE_ID); + + readAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + callback.onSuccess(value); + } + }, SENSOR_FAULT_ATTRIBUTE_ID, true); + } + + public void subscribeSensorFaultAttribute( + IntegerAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SENSOR_FAULT_ATTRIBUTE_ID); + + subscribeAttribute(new ReportCallbackImpl(callback, path) { + @Override + public void onSuccess(byte[] tlv) { + Integer value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + } + }, SENSOR_FAULT_ATTRIBUTE_ID, minInterval, maxInterval); } public void readGeneratedCommandListAttribute( diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java b/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java index 79d160371f9712..4ad4fd533b207d 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipEventStructs.java @@ -2907,13 +2907,13 @@ public String toString() { return output.toString(); } } -public static class BooleanSensorConfigurationClusterAlarmsStateChangedEvent { +public static class BooleanStateConfigurationClusterAlarmsStateChangedEvent { public Integer alarmsActive; public Optional alarmsSuppressed; private static final long ALARMS_ACTIVE_ID = 0L; private static final long ALARMS_SUPPRESSED_ID = 1L; - public BooleanSensorConfigurationClusterAlarmsStateChangedEvent( + public BooleanStateConfigurationClusterAlarmsStateChangedEvent( Integer alarmsActive, Optional alarmsSuppressed ) { @@ -2929,7 +2929,7 @@ public StructType encodeTlv() { return new StructType(values); } - public static BooleanSensorConfigurationClusterAlarmsStateChangedEvent decodeTlv(BaseTLVType tlvValue) { + public static BooleanStateConfigurationClusterAlarmsStateChangedEvent decodeTlv(BaseTLVType tlvValue) { if (tlvValue == null || tlvValue.type() != TLVType.Struct) { return null; } @@ -2948,7 +2948,7 @@ public static BooleanSensorConfigurationClusterAlarmsStateChangedEvent decodeTlv } } } - return new BooleanSensorConfigurationClusterAlarmsStateChangedEvent( + return new BooleanStateConfigurationClusterAlarmsStateChangedEvent( alarmsActive, alarmsSuppressed ); @@ -2957,7 +2957,7 @@ public static BooleanSensorConfigurationClusterAlarmsStateChangedEvent decodeTlv @Override public String toString() { StringBuilder output = new StringBuilder(); - output.append("BooleanSensorConfigurationClusterAlarmsStateChangedEvent {\n"); + output.append("BooleanStateConfigurationClusterAlarmsStateChangedEvent {\n"); output.append("\talarmsActive: "); output.append(alarmsActive); output.append("\n"); @@ -2968,6 +2968,52 @@ public String toString() { return output.toString(); } } +public static class BooleanStateConfigurationClusterSensorFaultEvent { + public Integer sensorFault; + private static final long SENSOR_FAULT_ID = 0L; + + public BooleanStateConfigurationClusterSensorFaultEvent( + Integer sensorFault + ) { + this.sensorFault = sensorFault; + } + + public StructType encodeTlv() { + ArrayList values = new ArrayList<>(); + values.add(new StructElement(SENSOR_FAULT_ID, new UIntType(sensorFault))); + + return new StructType(values); + } + + public static BooleanStateConfigurationClusterSensorFaultEvent decodeTlv(BaseTLVType tlvValue) { + if (tlvValue == null || tlvValue.type() != TLVType.Struct) { + return null; + } + Integer sensorFault = null; + for (StructElement element: ((StructType)tlvValue).value()) { + if (element.contextTagNum() == SENSOR_FAULT_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + sensorFault = castingValue.value(Integer.class); + } + } + } + return new BooleanStateConfigurationClusterSensorFaultEvent( + sensorFault + ); + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("BooleanStateConfigurationClusterSensorFaultEvent {\n"); + output.append("\tsensorFault: "); + output.append(sensorFault); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } +} public static class ValveConfigurationAndControlClusterValveStateChangedEvent { public Integer valveState; private static final long VALVE_STATE_ID = 0L; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java index cfdcfa8a6434d7..3b44c508979b8e 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java @@ -217,8 +217,8 @@ public static BaseCluster getCluster(long clusterId) { if (clusterId == ActivatedCarbonFilterMonitoring.ID) { return new ActivatedCarbonFilterMonitoring(); } - if (clusterId == BooleanSensorConfiguration.ID) { - return new BooleanSensorConfiguration(); + if (clusterId == BooleanStateConfiguration.ID) { + return new BooleanStateConfiguration(); } if (clusterId == ValveConfigurationAndControl.ID) { return new ValveConfigurationAndControl(); @@ -8768,17 +8768,21 @@ public long getCommandID(String name) throws IllegalArgumentException { return Command.valueOf(name).getID(); } } - public static class BooleanSensorConfiguration implements BaseCluster { + public static class BooleanStateConfiguration implements BaseCluster { public static final long ID = 128L; public long getID() { return ID; } public enum Attribute { - SensitivityLevel(0L), - AlarmsActive(1L), - AlarmsSuppressed(2L), - AlarmsEnabled(3L), + CurrentSensitivityLevel(0L), + SupportedSensitivityLevels(1L), + DefaultSensitivityLevel(2L), + AlarmsActive(3L), + AlarmsSuppressed(4L), + AlarmsEnabled(5L), + AlarmsSupported(6L), + SensorFault(7L), GeneratedCommandList(65528L), AcceptedCommandList(65529L), EventList(65530L), @@ -8827,7 +8831,8 @@ public static Event value(long id) throws NoSuchFieldError { } public enum Command { - SuppressRequest(0L),; + SuppressAlarm(0L), + EnableDisableAlarm(1L),; private final long id; Command(long id) { this.id = id; @@ -8845,17 +8850,34 @@ public static Command value(long id) throws NoSuchFieldError { } throw new NoSuchFieldError(); } - }public enum SuppressRequestCommandField {AlarmsToSuppress(0),; + }public enum SuppressAlarmCommandField {AlarmsToSuppress(0),; private final int id; - SuppressRequestCommandField(int id) { + SuppressAlarmCommandField(int id) { this.id = id; } public int getID() { return id; } - public static SuppressRequestCommandField value(int id) throws NoSuchFieldError { - for (SuppressRequestCommandField field : SuppressRequestCommandField.values()) { + public static SuppressAlarmCommandField value(int id) throws NoSuchFieldError { + for (SuppressAlarmCommandField field : SuppressAlarmCommandField.values()) { + if (field.getID() == id) { + return field; + } + } + throw new NoSuchFieldError(); + } + }public enum EnableDisableAlarmCommandField {AlarmsToEnableDisable(0),; + private final int id; + EnableDisableAlarmCommandField(int id) { + this.id = id; + } + + public int getID() { + return id; + } + public static EnableDisableAlarmCommandField value(int id) throws NoSuchFieldError { + for (EnableDisableAlarmCommandField field : EnableDisableAlarmCommandField.values()) { if (field.getID() == id) { return field; } diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 91b7d28b9fe564..390cd09f42544c 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -9672,7 +9672,7 @@ public void onError(Exception ex) { } } - public static class DelegatedBooleanSensorConfigurationClusterGeneratedCommandListAttributeCallback implements ChipClusters.BooleanSensorConfigurationCluster.GeneratedCommandListAttributeCallback, DelegatedClusterCallback { + public static class DelegatedBooleanStateConfigurationClusterGeneratedCommandListAttributeCallback implements ChipClusters.BooleanStateConfigurationCluster.GeneratedCommandListAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override public void setCallbackDelegate(ClusterCommandCallback callback) { @@ -9693,7 +9693,7 @@ public void onError(Exception ex) { } } - public static class DelegatedBooleanSensorConfigurationClusterAcceptedCommandListAttributeCallback implements ChipClusters.BooleanSensorConfigurationCluster.AcceptedCommandListAttributeCallback, DelegatedClusterCallback { + public static class DelegatedBooleanStateConfigurationClusterAcceptedCommandListAttributeCallback implements ChipClusters.BooleanStateConfigurationCluster.AcceptedCommandListAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override public void setCallbackDelegate(ClusterCommandCallback callback) { @@ -9714,7 +9714,7 @@ public void onError(Exception ex) { } } - public static class DelegatedBooleanSensorConfigurationClusterEventListAttributeCallback implements ChipClusters.BooleanSensorConfigurationCluster.EventListAttributeCallback, DelegatedClusterCallback { + public static class DelegatedBooleanStateConfigurationClusterEventListAttributeCallback implements ChipClusters.BooleanStateConfigurationCluster.EventListAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override public void setCallbackDelegate(ClusterCommandCallback callback) { @@ -9735,7 +9735,7 @@ public void onError(Exception ex) { } } - public static class DelegatedBooleanSensorConfigurationClusterAttributeListAttributeCallback implements ChipClusters.BooleanSensorConfigurationCluster.AttributeListAttributeCallback, DelegatedClusterCallback { + public static class DelegatedBooleanStateConfigurationClusterAttributeListAttributeCallback implements ChipClusters.BooleanStateConfigurationCluster.AttributeListAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override public void setCallbackDelegate(ClusterCommandCallback callback) { @@ -19546,9 +19546,9 @@ public Map initializeClusterMap() { (ptr, endpointId) -> new ChipClusters.ActivatedCarbonFilterMonitoringCluster(ptr, endpointId), new HashMap<>()); clusterMap.put("activatedCarbonFilterMonitoring", activatedCarbonFilterMonitoringClusterInfo); - ClusterInfo booleanSensorConfigurationClusterInfo = new ClusterInfo( - (ptr, endpointId) -> new ChipClusters.BooleanSensorConfigurationCluster(ptr, endpointId), new HashMap<>()); - clusterMap.put("booleanSensorConfiguration", booleanSensorConfigurationClusterInfo); + ClusterInfo booleanStateConfigurationClusterInfo = new ClusterInfo( + (ptr, endpointId) -> new ChipClusters.BooleanStateConfigurationCluster(ptr, endpointId), new HashMap<>()); + clusterMap.put("booleanStateConfiguration", booleanStateConfigurationClusterInfo); ClusterInfo valveConfigurationAndControlClusterInfo = new ClusterInfo( (ptr, endpointId) -> new ChipClusters.ValveConfigurationAndControlCluster(ptr, endpointId), new HashMap<>()); @@ -19809,7 +19809,7 @@ public void combineCommand(Map destination, Map> getCommandMap() { commandMap.put("activatedCarbonFilterMonitoring", activatedCarbonFilterMonitoringClusterInteractionInfoMap); - Map booleanSensorConfigurationClusterInteractionInfoMap = new LinkedHashMap<>(); + Map booleanStateConfigurationClusterInteractionInfoMap = new LinkedHashMap<>(); - Map booleanSensorConfigurationsuppressRequestCommandParams = new LinkedHashMap(); + Map booleanStateConfigurationsuppressAlarmCommandParams = new LinkedHashMap(); - CommandParameterInfo booleanSensorConfigurationsuppressRequestalarmsToSuppressCommandParameterInfo = new CommandParameterInfo("alarmsToSuppress", Integer.class, Integer.class); - booleanSensorConfigurationsuppressRequestCommandParams.put("alarmsToSuppress",booleanSensorConfigurationsuppressRequestalarmsToSuppressCommandParameterInfo); - InteractionInfo booleanSensorConfigurationsuppressRequestInteractionInfo = new InteractionInfo( + CommandParameterInfo booleanStateConfigurationsuppressAlarmalarmsToSuppressCommandParameterInfo = new CommandParameterInfo("alarmsToSuppress", Integer.class, Integer.class); + booleanStateConfigurationsuppressAlarmCommandParams.put("alarmsToSuppress",booleanStateConfigurationsuppressAlarmalarmsToSuppressCommandParameterInfo); + InteractionInfo booleanStateConfigurationsuppressAlarmInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster) - .suppressRequest((DefaultClusterCallback) callback + ((ChipClusters.BooleanStateConfigurationCluster) cluster) + .suppressAlarm((DefaultClusterCallback) callback , (Integer) commandArguments.get("alarmsToSuppress") ); }, () -> new DelegatedDefaultClusterCallback(), - booleanSensorConfigurationsuppressRequestCommandParams + booleanStateConfigurationsuppressAlarmCommandParams ); - booleanSensorConfigurationClusterInteractionInfoMap.put("suppressRequest", booleanSensorConfigurationsuppressRequestInteractionInfo); + booleanStateConfigurationClusterInteractionInfoMap.put("suppressAlarm", booleanStateConfigurationsuppressAlarmInteractionInfo); - commandMap.put("booleanSensorConfiguration", booleanSensorConfigurationClusterInteractionInfoMap); + Map booleanStateConfigurationenableDisableAlarmCommandParams = new LinkedHashMap(); + + CommandParameterInfo booleanStateConfigurationenableDisableAlarmalarmsToEnableDisableCommandParameterInfo = new CommandParameterInfo("alarmsToEnableDisable", Integer.class, Integer.class); + booleanStateConfigurationenableDisableAlarmCommandParams.put("alarmsToEnableDisable",booleanStateConfigurationenableDisableAlarmalarmsToEnableDisableCommandParameterInfo); + InteractionInfo booleanStateConfigurationenableDisableAlarmInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.BooleanStateConfigurationCluster) cluster) + .enableDisableAlarm((DefaultClusterCallback) callback + , (Integer) + commandArguments.get("alarmsToEnableDisable") + ); + }, + () -> new DelegatedDefaultClusterCallback(), + booleanStateConfigurationenableDisableAlarmCommandParams + ); + booleanStateConfigurationClusterInteractionInfoMap.put("enableDisableAlarm", booleanStateConfigurationenableDisableAlarmInteractionInfo); + + commandMap.put("booleanStateConfiguration", booleanStateConfigurationClusterInteractionInfoMap); Map valveConfigurationAndControlClusterInteractionInfoMap = new LinkedHashMap<>(); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java index ec96ce4c2bc8a7..5e36aca034a4c2 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java @@ -8637,117 +8637,161 @@ private static Map readActivatedCarbonFilterMonitoringI return result; } - private static Map readBooleanSensorConfigurationInteractionInfo() { - Map result = new LinkedHashMap<>();Map readBooleanSensorConfigurationSensitivityLevelCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationSensitivityLevelAttributeInteractionInfo = new InteractionInfo( + private static Map readBooleanStateConfigurationInteractionInfo() { + Map result = new LinkedHashMap<>();Map readBooleanStateConfigurationCurrentSensitivityLevelCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationCurrentSensitivityLevelAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readSensitivityLevelAttribute( + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readCurrentSensitivityLevelAttribute( (ChipClusters.IntegerAttributeCallback) callback ); }, () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), - readBooleanSensorConfigurationSensitivityLevelCommandParams + readBooleanStateConfigurationCurrentSensitivityLevelCommandParams ); - result.put("readSensitivityLevelAttribute", readBooleanSensorConfigurationSensitivityLevelAttributeInteractionInfo); - Map readBooleanSensorConfigurationAlarmsActiveCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationAlarmsActiveAttributeInteractionInfo = new InteractionInfo( + result.put("readCurrentSensitivityLevelAttribute", readBooleanStateConfigurationCurrentSensitivityLevelAttributeInteractionInfo); + Map readBooleanStateConfigurationSupportedSensitivityLevelsCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationSupportedSensitivityLevelsAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readAlarmsActiveAttribute( + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readSupportedSensitivityLevelsAttribute( (ChipClusters.IntegerAttributeCallback) callback ); }, () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), - readBooleanSensorConfigurationAlarmsActiveCommandParams + readBooleanStateConfigurationSupportedSensitivityLevelsCommandParams ); - result.put("readAlarmsActiveAttribute", readBooleanSensorConfigurationAlarmsActiveAttributeInteractionInfo); - Map readBooleanSensorConfigurationAlarmsSuppressedCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationAlarmsSuppressedAttributeInteractionInfo = new InteractionInfo( + result.put("readSupportedSensitivityLevelsAttribute", readBooleanStateConfigurationSupportedSensitivityLevelsAttributeInteractionInfo); + Map readBooleanStateConfigurationDefaultSensitivityLevelCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationDefaultSensitivityLevelAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readAlarmsSuppressedAttribute( + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readDefaultSensitivityLevelAttribute( (ChipClusters.IntegerAttributeCallback) callback ); }, () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), - readBooleanSensorConfigurationAlarmsSuppressedCommandParams + readBooleanStateConfigurationDefaultSensitivityLevelCommandParams ); - result.put("readAlarmsSuppressedAttribute", readBooleanSensorConfigurationAlarmsSuppressedAttributeInteractionInfo); - Map readBooleanSensorConfigurationAlarmsEnabledCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationAlarmsEnabledAttributeInteractionInfo = new InteractionInfo( + result.put("readDefaultSensitivityLevelAttribute", readBooleanStateConfigurationDefaultSensitivityLevelAttributeInteractionInfo); + Map readBooleanStateConfigurationAlarmsActiveCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationAlarmsActiveAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readAlarmsEnabledAttribute( + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readAlarmsActiveAttribute( (ChipClusters.IntegerAttributeCallback) callback ); }, () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), - readBooleanSensorConfigurationAlarmsEnabledCommandParams + readBooleanStateConfigurationAlarmsActiveCommandParams ); - result.put("readAlarmsEnabledAttribute", readBooleanSensorConfigurationAlarmsEnabledAttributeInteractionInfo); - Map readBooleanSensorConfigurationGeneratedCommandListCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationGeneratedCommandListAttributeInteractionInfo = new InteractionInfo( + result.put("readAlarmsActiveAttribute", readBooleanStateConfigurationAlarmsActiveAttributeInteractionInfo); + Map readBooleanStateConfigurationAlarmsSuppressedCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationAlarmsSuppressedAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readGeneratedCommandListAttribute( - (ChipClusters.BooleanSensorConfigurationCluster.GeneratedCommandListAttributeCallback) callback + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readAlarmsSuppressedAttribute( + (ChipClusters.IntegerAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), + readBooleanStateConfigurationAlarmsSuppressedCommandParams + ); + result.put("readAlarmsSuppressedAttribute", readBooleanStateConfigurationAlarmsSuppressedAttributeInteractionInfo); + Map readBooleanStateConfigurationAlarmsEnabledCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationAlarmsEnabledAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readAlarmsEnabledAttribute( + (ChipClusters.IntegerAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), + readBooleanStateConfigurationAlarmsEnabledCommandParams + ); + result.put("readAlarmsEnabledAttribute", readBooleanStateConfigurationAlarmsEnabledAttributeInteractionInfo); + Map readBooleanStateConfigurationAlarmsSupportedCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationAlarmsSupportedAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readAlarmsSupportedAttribute( + (ChipClusters.IntegerAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), + readBooleanStateConfigurationAlarmsSupportedCommandParams + ); + result.put("readAlarmsSupportedAttribute", readBooleanStateConfigurationAlarmsSupportedAttributeInteractionInfo); + Map readBooleanStateConfigurationSensorFaultCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationSensorFaultAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readSensorFaultAttribute( + (ChipClusters.IntegerAttributeCallback) callback + ); + }, + () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), + readBooleanStateConfigurationSensorFaultCommandParams + ); + result.put("readSensorFaultAttribute", readBooleanStateConfigurationSensorFaultAttributeInteractionInfo); + Map readBooleanStateConfigurationGeneratedCommandListCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationGeneratedCommandListAttributeInteractionInfo = new InteractionInfo( + (cluster, callback, commandArguments) -> { + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readGeneratedCommandListAttribute( + (ChipClusters.BooleanStateConfigurationCluster.GeneratedCommandListAttributeCallback) callback ); }, - () -> new ClusterInfoMapping.DelegatedBooleanSensorConfigurationClusterGeneratedCommandListAttributeCallback(), - readBooleanSensorConfigurationGeneratedCommandListCommandParams + () -> new ClusterInfoMapping.DelegatedBooleanStateConfigurationClusterGeneratedCommandListAttributeCallback(), + readBooleanStateConfigurationGeneratedCommandListCommandParams ); - result.put("readGeneratedCommandListAttribute", readBooleanSensorConfigurationGeneratedCommandListAttributeInteractionInfo); - Map readBooleanSensorConfigurationAcceptedCommandListCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationAcceptedCommandListAttributeInteractionInfo = new InteractionInfo( + result.put("readGeneratedCommandListAttribute", readBooleanStateConfigurationGeneratedCommandListAttributeInteractionInfo); + Map readBooleanStateConfigurationAcceptedCommandListCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationAcceptedCommandListAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readAcceptedCommandListAttribute( - (ChipClusters.BooleanSensorConfigurationCluster.AcceptedCommandListAttributeCallback) callback + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readAcceptedCommandListAttribute( + (ChipClusters.BooleanStateConfigurationCluster.AcceptedCommandListAttributeCallback) callback ); }, - () -> new ClusterInfoMapping.DelegatedBooleanSensorConfigurationClusterAcceptedCommandListAttributeCallback(), - readBooleanSensorConfigurationAcceptedCommandListCommandParams + () -> new ClusterInfoMapping.DelegatedBooleanStateConfigurationClusterAcceptedCommandListAttributeCallback(), + readBooleanStateConfigurationAcceptedCommandListCommandParams ); - result.put("readAcceptedCommandListAttribute", readBooleanSensorConfigurationAcceptedCommandListAttributeInteractionInfo); - Map readBooleanSensorConfigurationEventListCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationEventListAttributeInteractionInfo = new InteractionInfo( + result.put("readAcceptedCommandListAttribute", readBooleanStateConfigurationAcceptedCommandListAttributeInteractionInfo); + Map readBooleanStateConfigurationEventListCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationEventListAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readEventListAttribute( - (ChipClusters.BooleanSensorConfigurationCluster.EventListAttributeCallback) callback + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readEventListAttribute( + (ChipClusters.BooleanStateConfigurationCluster.EventListAttributeCallback) callback ); }, - () -> new ClusterInfoMapping.DelegatedBooleanSensorConfigurationClusterEventListAttributeCallback(), - readBooleanSensorConfigurationEventListCommandParams + () -> new ClusterInfoMapping.DelegatedBooleanStateConfigurationClusterEventListAttributeCallback(), + readBooleanStateConfigurationEventListCommandParams ); - result.put("readEventListAttribute", readBooleanSensorConfigurationEventListAttributeInteractionInfo); - Map readBooleanSensorConfigurationAttributeListCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationAttributeListAttributeInteractionInfo = new InteractionInfo( + result.put("readEventListAttribute", readBooleanStateConfigurationEventListAttributeInteractionInfo); + Map readBooleanStateConfigurationAttributeListCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationAttributeListAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readAttributeListAttribute( - (ChipClusters.BooleanSensorConfigurationCluster.AttributeListAttributeCallback) callback + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readAttributeListAttribute( + (ChipClusters.BooleanStateConfigurationCluster.AttributeListAttributeCallback) callback ); }, - () -> new ClusterInfoMapping.DelegatedBooleanSensorConfigurationClusterAttributeListAttributeCallback(), - readBooleanSensorConfigurationAttributeListCommandParams + () -> new ClusterInfoMapping.DelegatedBooleanStateConfigurationClusterAttributeListAttributeCallback(), + readBooleanStateConfigurationAttributeListCommandParams ); - result.put("readAttributeListAttribute", readBooleanSensorConfigurationAttributeListAttributeInteractionInfo); - Map readBooleanSensorConfigurationFeatureMapCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationFeatureMapAttributeInteractionInfo = new InteractionInfo( + result.put("readAttributeListAttribute", readBooleanStateConfigurationAttributeListAttributeInteractionInfo); + Map readBooleanStateConfigurationFeatureMapCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationFeatureMapAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readFeatureMapAttribute( + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readFeatureMapAttribute( (ChipClusters.LongAttributeCallback) callback ); }, () -> new ClusterInfoMapping.DelegatedLongAttributeCallback(), - readBooleanSensorConfigurationFeatureMapCommandParams + readBooleanStateConfigurationFeatureMapCommandParams ); - result.put("readFeatureMapAttribute", readBooleanSensorConfigurationFeatureMapAttributeInteractionInfo); - Map readBooleanSensorConfigurationClusterRevisionCommandParams = new LinkedHashMap(); - InteractionInfo readBooleanSensorConfigurationClusterRevisionAttributeInteractionInfo = new InteractionInfo( + result.put("readFeatureMapAttribute", readBooleanStateConfigurationFeatureMapAttributeInteractionInfo); + Map readBooleanStateConfigurationClusterRevisionCommandParams = new LinkedHashMap(); + InteractionInfo readBooleanStateConfigurationClusterRevisionAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).readClusterRevisionAttribute( + ((ChipClusters.BooleanStateConfigurationCluster) cluster).readClusterRevisionAttribute( (ChipClusters.IntegerAttributeCallback) callback ); }, () -> new ClusterInfoMapping.DelegatedIntegerAttributeCallback(), - readBooleanSensorConfigurationClusterRevisionCommandParams + readBooleanStateConfigurationClusterRevisionCommandParams ); - result.put("readClusterRevisionAttribute", readBooleanSensorConfigurationClusterRevisionAttributeInteractionInfo); + result.put("readClusterRevisionAttribute", readBooleanStateConfigurationClusterRevisionAttributeInteractionInfo); return result; } @@ -19460,7 +19504,7 @@ public Map> getReadAttributeMap() { put("rvcOperationalState", readRvcOperationalStateInteractionInfo()); put("hepaFilterMonitoring", readHepaFilterMonitoringInteractionInfo()); put("activatedCarbonFilterMonitoring", readActivatedCarbonFilterMonitoringInteractionInfo()); - put("booleanSensorConfiguration", readBooleanSensorConfigurationInteractionInfo()); + put("booleanStateConfiguration", readBooleanStateConfigurationInteractionInfo()); put("valveConfigurationAndControl", readValveConfigurationAndControlInteractionInfo()); put("electricalEnergyMeasurement", readElectricalEnergyMeasurementInteractionInfo()); put("demandResponseLoadControl", readDemandResponseLoadControlInteractionInfo()); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java index 5c6174336ce03a..3db35dfd2b3970 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java @@ -1164,52 +1164,30 @@ public Map> getWriteAttributeMap() { ); writeActivatedCarbonFilterMonitoringInteractionInfo.put("writeLastChangedTimeAttribute", writeActivatedCarbonFilterMonitoringLastChangedTimeAttributeInteractionInfo); writeAttributeMap.put("activatedCarbonFilterMonitoring", writeActivatedCarbonFilterMonitoringInteractionInfo); - Map writeBooleanSensorConfigurationInteractionInfo = new LinkedHashMap<>(); - Map writeBooleanSensorConfigurationSensitivityLevelCommandParams = new LinkedHashMap(); - CommandParameterInfo booleanSensorConfigurationsensitivityLevelCommandParameterInfo = + Map writeBooleanStateConfigurationInteractionInfo = new LinkedHashMap<>(); + Map writeBooleanStateConfigurationCurrentSensitivityLevelCommandParams = new LinkedHashMap(); + CommandParameterInfo booleanStateConfigurationcurrentSensitivityLevelCommandParameterInfo = new CommandParameterInfo( "value", Integer.class, Integer.class ); - writeBooleanSensorConfigurationSensitivityLevelCommandParams.put( + writeBooleanStateConfigurationCurrentSensitivityLevelCommandParams.put( "value", - booleanSensorConfigurationsensitivityLevelCommandParameterInfo + booleanStateConfigurationcurrentSensitivityLevelCommandParameterInfo ); - InteractionInfo writeBooleanSensorConfigurationSensitivityLevelAttributeInteractionInfo = new InteractionInfo( + InteractionInfo writeBooleanStateConfigurationCurrentSensitivityLevelAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).writeSensitivityLevelAttribute( + ((ChipClusters.BooleanStateConfigurationCluster) cluster).writeCurrentSensitivityLevelAttribute( (DefaultClusterCallback) callback, (Integer) commandArguments.get("value") ); }, () -> new ClusterInfoMapping.DelegatedDefaultClusterCallback(), - writeBooleanSensorConfigurationSensitivityLevelCommandParams + writeBooleanStateConfigurationCurrentSensitivityLevelCommandParams ); - writeBooleanSensorConfigurationInteractionInfo.put("writeSensitivityLevelAttribute", writeBooleanSensorConfigurationSensitivityLevelAttributeInteractionInfo); - Map writeBooleanSensorConfigurationAlarmsEnabledCommandParams = new LinkedHashMap(); - CommandParameterInfo booleanSensorConfigurationalarmsEnabledCommandParameterInfo = - new CommandParameterInfo( - "value", - Integer.class, - Integer.class - ); - writeBooleanSensorConfigurationAlarmsEnabledCommandParams.put( - "value", - booleanSensorConfigurationalarmsEnabledCommandParameterInfo - ); - InteractionInfo writeBooleanSensorConfigurationAlarmsEnabledAttributeInteractionInfo = new InteractionInfo( - (cluster, callback, commandArguments) -> { - ((ChipClusters.BooleanSensorConfigurationCluster) cluster).writeAlarmsEnabledAttribute( - (DefaultClusterCallback) callback, - (Integer) commandArguments.get("value") - ); - }, - () -> new ClusterInfoMapping.DelegatedDefaultClusterCallback(), - writeBooleanSensorConfigurationAlarmsEnabledCommandParams - ); - writeBooleanSensorConfigurationInteractionInfo.put("writeAlarmsEnabledAttribute", writeBooleanSensorConfigurationAlarmsEnabledAttributeInteractionInfo); - writeAttributeMap.put("booleanSensorConfiguration", writeBooleanSensorConfigurationInteractionInfo); + writeBooleanStateConfigurationInteractionInfo.put("writeCurrentSensitivityLevelAttribute", writeBooleanStateConfigurationCurrentSensitivityLevelAttributeInteractionInfo); + writeAttributeMap.put("booleanStateConfiguration", writeBooleanStateConfigurationInteractionInfo); Map writeValveConfigurationAndControlInteractionInfo = new LinkedHashMap<>(); Map writeValveConfigurationAndControlOpenDurationCommandParams = new LinkedHashMap(); CommandParameterInfo valveConfigurationAndControlopenDurationCommandParameterInfo = diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt similarity index 86% rename from src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt rename to src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt index c51a8e06724875..4c7e0fd2bb6110 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt @@ -23,12 +23,12 @@ import matter.tlv.Tag import matter.tlv.TlvReader import matter.tlv.TlvWriter -class BooleanSensorConfigurationClusterAlarmsStateChangedEvent( +class BooleanStateConfigurationClusterAlarmsStateChangedEvent( val alarmsActive: UInt, val alarmsSuppressed: Optional ) { override fun toString(): String = buildString { - append("BooleanSensorConfigurationClusterAlarmsStateChangedEvent {\n") + append("BooleanStateConfigurationClusterAlarmsStateChangedEvent {\n") append("\talarmsActive : $alarmsActive\n") append("\talarmsSuppressed : $alarmsSuppressed\n") append("}\n") @@ -53,7 +53,7 @@ class BooleanSensorConfigurationClusterAlarmsStateChangedEvent( fun fromTlv( tlvTag: Tag, tlvReader: TlvReader - ): BooleanSensorConfigurationClusterAlarmsStateChangedEvent { + ): BooleanStateConfigurationClusterAlarmsStateChangedEvent { tlvReader.enterStructure(tlvTag) val alarmsActive = tlvReader.getUInt(ContextSpecificTag(TAG_ALARMS_ACTIVE)) val alarmsSuppressed = @@ -65,10 +65,7 @@ class BooleanSensorConfigurationClusterAlarmsStateChangedEvent( tlvReader.exitContainer() - return BooleanSensorConfigurationClusterAlarmsStateChangedEvent( - alarmsActive, - alarmsSuppressed - ) + return BooleanStateConfigurationClusterAlarmsStateChangedEvent(alarmsActive, alarmsSuppressed) } } } diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt new file mode 100644 index 00000000000000..6232f56300e520 --- /dev/null +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package chip.devicecontroller.cluster.eventstructs + +import chip.devicecontroller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class BooleanStateConfigurationClusterSensorFaultEvent(val sensorFault: UInt) { + override fun toString(): String = buildString { + append("BooleanStateConfigurationClusterSensorFaultEvent {\n") + append("\tsensorFault : $sensorFault\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_SENSOR_FAULT), sensorFault) + endStructure() + } + } + + companion object { + private const val TAG_SENSOR_FAULT = 0 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader + ): BooleanStateConfigurationClusterSensorFaultEvent { + tlvReader.enterStructure(tlvTag) + val sensorFault = tlvReader.getUInt(ContextSpecificTag(TAG_SENSOR_FAULT)) + + tlvReader.exitContainer() + + return BooleanStateConfigurationClusterSensorFaultEvent(sensorFault) + } + } +} diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni index 6180ecae906183..363e418f960f6d 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni @@ -131,8 +131,9 @@ eventstructs_sources = [ "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BasicInformationClusterLeaveEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BasicInformationClusterReachableChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BasicInformationClusterStartUpEvent.kt", - "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateClusterStateChangeEvent.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterReachableChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/BridgedDeviceBasicInformationClusterStartUpEvent.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/eventstructs/DemandResponseLoadControlClusterLoadControlEventStatusChangeEvent.kt", diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanSensorConfigurationCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanStateConfigurationCluster.kt similarity index 72% rename from src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanSensorConfigurationCluster.kt rename to src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanStateConfigurationCluster.kt index 510d0c3e4f3db4..3cbd118dac1c2e 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanSensorConfigurationCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanStateConfigurationCluster.kt @@ -43,7 +43,7 @@ import matter.tlv.ContextSpecificTag import matter.tlv.TlvReader import matter.tlv.TlvWriter -class BooleanSensorConfigurationCluster( +class BooleanStateConfigurationCluster( private val controller: MatterController, private val endpointId: UShort ) { @@ -87,7 +87,7 @@ class BooleanSensorConfigurationCluster( object SubscriptionEstablished : AttributeListAttributeSubscriptionState() } - suspend fun suppressRequest(alarmsToSuppress: UByte, timedInvokeTimeout: Duration? = null) { + suspend fun suppressAlarm(alarmsToSuppress: UByte, timedInvokeTimeout: Duration? = null) { val commandId: UInt = 0u val tlvWriter = TlvWriter() @@ -108,7 +108,31 @@ class BooleanSensorConfigurationCluster( logger.log(Level.FINE, "Invoke command succeeded: ${response}") } - suspend fun readSensitivityLevelAttribute(): UByte? { + suspend fun enableDisableAlarm( + alarmsToEnableDisable: UByte, + timedInvokeTimeout: Duration? = null + ) { + val commandId: UInt = 1u + + val tlvWriter = TlvWriter() + tlvWriter.startStructure(AnonymousTag) + + val TAG_ALARMS_TO_ENABLE_DISABLE_REQ: Int = 0 + tlvWriter.put(ContextSpecificTag(TAG_ALARMS_TO_ENABLE_DISABLE_REQ), alarmsToEnableDisable) + tlvWriter.endStructure() + + val request: InvokeRequest = + InvokeRequest( + CommandPath(endpointId, clusterId = CLUSTER_ID, commandId), + tlvPayload = tlvWriter.getEncoded(), + timedRequest = timedInvokeTimeout + ) + + val response: InvokeResponse = controller.invoke(request) + logger.log(Level.FINE, "Invoke command succeeded: ${response}") + } + + suspend fun readCurrentSensitivityLevelAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 0u val attributePath = @@ -130,7 +154,7 @@ class BooleanSensorConfigurationCluster( it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { "Sensitivitylevel attribute not found in response" } + requireNotNull(attributeData) { "Currentsensitivitylevel attribute not found in response" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) @@ -144,7 +168,10 @@ class BooleanSensorConfigurationCluster( return decodedValue } - suspend fun writeSensitivityLevelAttribute(value: UByte, timedWriteTimeout: Duration? = null) { + suspend fun writeCurrentSensitivityLevelAttribute( + value: UByte, + timedWriteTimeout: Duration? = null + ) { val ATTRIBUTE_ID: UInt = 0u val tlvWriter = TlvWriter() @@ -184,7 +211,7 @@ class BooleanSensorConfigurationCluster( } } - suspend fun subscribeSensitivityLevelAttribute( + suspend fun subscribeCurrentSensitivityLevelAttribute( minInterval: Int, maxInterval: Int ): Flow { @@ -220,7 +247,7 @@ class BooleanSensorConfigurationCluster( .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } requireNotNull(attributeData) { - "Sensitivitylevel attribute not found in Node State update" + "Currentsensitivitylevel attribute not found in Node State update" } // Decode the TLV data into the appropriate type @@ -241,7 +268,7 @@ class BooleanSensorConfigurationCluster( } } - suspend fun readAlarmsActiveAttribute(): UByte? { + suspend fun readSupportedSensitivityLevelsAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 1u val attributePath = @@ -263,7 +290,7 @@ class BooleanSensorConfigurationCluster( it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { "Alarmsactive attribute not found in response" } + requireNotNull(attributeData) { "Supportedsensitivitylevels attribute not found in response" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) @@ -277,7 +304,7 @@ class BooleanSensorConfigurationCluster( return decodedValue } - suspend fun subscribeAlarmsActiveAttribute( + suspend fun subscribeSupportedSensitivityLevelsAttribute( minInterval: Int, maxInterval: Int ): Flow { @@ -312,7 +339,9 @@ class BooleanSensorConfigurationCluster( .filterIsInstance() .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { "Alarmsactive attribute not found in Node State update" } + requireNotNull(attributeData) { + "Supportedsensitivitylevels attribute not found in Node State update" + } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) @@ -332,7 +361,7 @@ class BooleanSensorConfigurationCluster( } } - suspend fun readAlarmsSuppressedAttribute(): UByte? { + suspend fun readDefaultSensitivityLevelAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 2u val attributePath = @@ -354,7 +383,7 @@ class BooleanSensorConfigurationCluster( it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { "Alarmssuppressed attribute not found in response" } + requireNotNull(attributeData) { "Defaultsensitivitylevel attribute not found in response" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) @@ -368,7 +397,7 @@ class BooleanSensorConfigurationCluster( return decodedValue } - suspend fun subscribeAlarmsSuppressedAttribute( + suspend fun subscribeDefaultSensitivityLevelAttribute( minInterval: Int, maxInterval: Int ): Flow { @@ -404,7 +433,7 @@ class BooleanSensorConfigurationCluster( .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } requireNotNull(attributeData) { - "Alarmssuppressed attribute not found in Node State update" + "Defaultsensitivitylevel attribute not found in Node State update" } // Decode the TLV data into the appropriate type @@ -425,7 +454,7 @@ class BooleanSensorConfigurationCluster( } } - suspend fun readAlarmsEnabledAttribute(): UByte? { + suspend fun readAlarmsActiveAttribute(): UByte? { val ATTRIBUTE_ID: UInt = 3u val attributePath = @@ -447,7 +476,7 @@ class BooleanSensorConfigurationCluster( it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { "Alarmsenabled attribute not found in response" } + requireNotNull(attributeData) { "Alarmsactive attribute not found in response" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) @@ -461,51 +490,195 @@ class BooleanSensorConfigurationCluster( return decodedValue } - suspend fun writeAlarmsEnabledAttribute(value: UByte, timedWriteTimeout: Duration? = null) { + suspend fun subscribeAlarmsActiveAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { val ATTRIBUTE_ID: UInt = 3u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, value) + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) - val writeRequests: WriteRequests = - WriteRequests( - requests = - listOf( - WriteRequest( - attributePath = - AttributePath(endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID), - tlvPayload = tlvWriter.getEncoded() + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) ) - ), - timedRequest = timedWriteTimeout - ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } - val response: WriteResponse = controller.write(writeRequests) + requireNotNull(attributeData) { "Alarmsactive attribute not found in Node State update" } - when (response) { - is WriteResponse.Success -> { - logger.log(Level.FINE, "Write command succeeded") + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } } - is WriteResponse.PartialWriteFailure -> { - val aggregatedErrorMessage = - response.failures.joinToString("\n") { failure -> - "Error at ${failure.attributePath}: ${failure.ex.message}" - } + } + } - response.failures.forEach { failure -> - logger.log(Level.WARNING, "Error at ${failure.attributePath}: ${failure.ex.message}") + suspend fun readAlarmsSuppressedAttribute(): UByte? { + val ATTRIBUTE_ID: UInt = 4u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Alarmssuppressed attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + return decodedValue + } + + suspend fun subscribeAlarmsSuppressedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 4u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } - throw IllegalStateException("Write command failed with errors: \n$aggregatedErrorMessage") + requireNotNull(attributeData) { + "Alarmssuppressed attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } } } } + suspend fun readAlarmsEnabledAttribute(): UByte? { + val ATTRIBUTE_ID: UInt = 5u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Alarmsenabled attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + return decodedValue + } + suspend fun subscribeAlarmsEnabledAttribute( minInterval: Int, maxInterval: Int ): Flow { - val ATTRIBUTE_ID: UInt = 3u + val ATTRIBUTE_ID: UInt = 5u val attributePaths = listOf( AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) @@ -556,6 +729,190 @@ class BooleanSensorConfigurationCluster( } } + suspend fun readAlarmsSupportedAttribute(): UByte? { + val ATTRIBUTE_ID: UInt = 6u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Alarmssupported attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + return decodedValue + } + + suspend fun subscribeAlarmsSupportedAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 6u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UByteSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { + "Alarmssupported attribute not found in Node State update" + } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UByte? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUByte(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UByteSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UByteSubscriptionState.SubscriptionEstablished) + } + } + } + } + + suspend fun readSensorFaultAttribute(): UShort? { + val ATTRIBUTE_ID: UInt = 7u + + val attributePath = + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + + val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) + + val response = controller.read(readRequest) + + if (response.successes.isEmpty()) { + logger.log(Level.WARNING, "Read command failed") + throw IllegalStateException("Read command failed with failures: ${response.failures}") + } + + logger.log(Level.FINE, "Read command succeeded") + + val attributeData = + response.successes.filterIsInstance().firstOrNull { + it.path.attributeId == ATTRIBUTE_ID + } + + requireNotNull(attributeData) { "Sensorfault attribute not found in response" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + return decodedValue + } + + suspend fun subscribeSensorFaultAttribute( + minInterval: Int, + maxInterval: Int + ): Flow { + val ATTRIBUTE_ID: UInt = 7u + val attributePaths = + listOf( + AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) + ) + + val subscribeRequest: SubscribeRequest = + SubscribeRequest( + eventPaths = emptyList(), + attributePaths = attributePaths, + minInterval = Duration.ofSeconds(minInterval.toLong()), + maxInterval = Duration.ofSeconds(maxInterval.toLong()) + ) + + return controller.subscribe(subscribeRequest).transform { subscriptionState -> + when (subscriptionState) { + is SubscriptionState.SubscriptionErrorNotification -> { + emit( + UShortSubscriptionState.Error( + Exception( + "Subscription terminated with error code: ${subscriptionState.terminationCause}" + ) + ) + ) + } + is SubscriptionState.NodeStateUpdate -> { + val attributeData = + subscriptionState.updateState.successes + .filterIsInstance() + .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } + + requireNotNull(attributeData) { "Sensorfault attribute not found in Node State update" } + + // Decode the TLV data into the appropriate type + val tlvReader = TlvReader(attributeData.data) + val decodedValue: UShort? = + if (tlvReader.isNextTag(AnonymousTag)) { + tlvReader.getUShort(AnonymousTag) + } else { + null + } + + decodedValue?.let { emit(UShortSubscriptionState.Success(it)) } + } + SubscriptionState.SubscriptionEstablished -> { + emit(UShortSubscriptionState.SubscriptionEstablished) + } + } + } + } + suspend fun readGeneratedCommandListAttribute(): GeneratedCommandListAttribute { val ATTRIBUTE_ID: UInt = 65528u @@ -1105,7 +1462,7 @@ class BooleanSensorConfigurationCluster( } companion object { - private val logger = Logger.getLogger(BooleanSensorConfigurationCluster::class.java.name) + private val logger = Logger.getLogger(BooleanStateConfigurationCluster::class.java.name) const val CLUSTER_ID: UInt = 128u } } diff --git a/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt b/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt similarity index 86% rename from src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt rename to src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt index 3918c2c126485e..f6777c819c9a57 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt @@ -23,12 +23,12 @@ import matter.tlv.Tag import matter.tlv.TlvReader import matter.tlv.TlvWriter -class BooleanSensorConfigurationClusterAlarmsStateChangedEvent( +class BooleanStateConfigurationClusterAlarmsStateChangedEvent( val alarmsActive: UByte, val alarmsSuppressed: Optional ) { override fun toString(): String = buildString { - append("BooleanSensorConfigurationClusterAlarmsStateChangedEvent {\n") + append("BooleanStateConfigurationClusterAlarmsStateChangedEvent {\n") append("\talarmsActive : $alarmsActive\n") append("\talarmsSuppressed : $alarmsSuppressed\n") append("}\n") @@ -53,7 +53,7 @@ class BooleanSensorConfigurationClusterAlarmsStateChangedEvent( fun fromTlv( tlvTag: Tag, tlvReader: TlvReader - ): BooleanSensorConfigurationClusterAlarmsStateChangedEvent { + ): BooleanStateConfigurationClusterAlarmsStateChangedEvent { tlvReader.enterStructure(tlvTag) val alarmsActive = tlvReader.getUByte(ContextSpecificTag(TAG_ALARMS_ACTIVE)) val alarmsSuppressed = @@ -65,10 +65,7 @@ class BooleanSensorConfigurationClusterAlarmsStateChangedEvent( tlvReader.exitContainer() - return BooleanSensorConfigurationClusterAlarmsStateChangedEvent( - alarmsActive, - alarmsSuppressed - ) + return BooleanStateConfigurationClusterAlarmsStateChangedEvent(alarmsActive, alarmsSuppressed) } } } diff --git a/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt b/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt new file mode 100644 index 00000000000000..d29696d04cc3bf --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package matter.controller.cluster.eventstructs + +import matter.controller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class BooleanStateConfigurationClusterSensorFaultEvent(val sensorFault: UShort) { + override fun toString(): String = buildString { + append("BooleanStateConfigurationClusterSensorFaultEvent {\n") + append("\tsensorFault : $sensorFault\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_SENSOR_FAULT), sensorFault) + endStructure() + } + } + + companion object { + private const val TAG_SENSOR_FAULT = 0 + + fun fromTlv( + tlvTag: Tag, + tlvReader: TlvReader + ): BooleanStateConfigurationClusterSensorFaultEvent { + tlvReader.enterStructure(tlvTag) + val sensorFault = tlvReader.getUShort(ContextSpecificTag(TAG_SENSOR_FAULT)) + + tlvReader.exitContainer() + + return BooleanStateConfigurationClusterSensorFaultEvent(sensorFault) + } + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/files.gni b/src/controller/java/generated/java/matter/controller/cluster/files.gni index d7d18479992e91..ff107deb40dcbb 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/files.gni +++ b/src/controller/java/generated/java/matter/controller/cluster/files.gni @@ -131,8 +131,9 @@ matter_eventstructs_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BasicInformationClusterLeaveEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BasicInformationClusterReachableChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BasicInformationClusterStartUpEvent.kt", - "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanSensorConfigurationClusterAlarmsStateChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateClusterStateChangeEvent.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterAlarmsStateChangedEvent.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BooleanStateConfigurationClusterSensorFaultEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterReachableChangedEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/BridgedDeviceBasicInformationClusterStartUpEvent.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/eventstructs/DemandResponseLoadControlClusterLoadControlEventStatusChangeEvent.kt", @@ -212,8 +213,8 @@ matter_clusters_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/BasicInformationCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/BinaryInputBasicCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/BindingCluster.kt", - "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanSensorConfigurationCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanStateCluster.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/BooleanStateConfigurationCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/BridgedDeviceBasicInformationCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonDioxideConcentrationMeasurementCluster.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/clusters/CarbonMonoxideConcentrationMeasurementCluster.kt", diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index b1764fa2e9a1be..5fba45d25734e3 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -18781,12 +18781,44 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } break; } - case app::Clusters::BooleanSensorConfiguration::Id: { - using namespace app::Clusters::BooleanSensorConfiguration; + case app::Clusters::BooleanStateConfiguration::Id: { + using namespace app::Clusters::BooleanStateConfiguration; switch (aPath.mAttributeId) { - case Attributes::SensitivityLevel::Id: { - using TypeInfo = Attributes::SensitivityLevel::TypeInfo; + case Attributes::CurrentSensitivityLevel::Id: { + using TypeInfo = Attributes::CurrentSensitivityLevel::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Integer"; + std::string valueCtorSignature = "(I)V"; + jint jnivalue = static_cast(cppValue); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), jnivalue, + value); + return value; + } + case Attributes::SupportedSensitivityLevels::Id: { + using TypeInfo = Attributes::SupportedSensitivityLevels::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Integer"; + std::string valueCtorSignature = "(I)V"; + jint jnivalue = static_cast(cppValue); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), jnivalue, + value); + return value; + } + case Attributes::DefaultSensitivityLevel::Id: { + using TypeInfo = Attributes::DefaultSensitivityLevel::TypeInfo; TypeInfo::DecodableType cppValue; *aError = app::DataModel::Decode(aReader, cppValue); if (*aError != CHIP_NO_ERROR) @@ -18849,6 +18881,38 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR value); return value; } + case Attributes::AlarmsSupported::Id: { + using TypeInfo = Attributes::AlarmsSupported::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Integer"; + std::string valueCtorSignature = "(I)V"; + jint jnivalue = static_cast(cppValue.Raw()); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), jnivalue, + value); + return value; + } + case Attributes::SensorFault::Id: { + using TypeInfo = Attributes::SensorFault::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = app::DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) + { + return nullptr; + } + jobject value; + std::string valueClassName = "java/lang/Integer"; + std::string valueCtorSignature = "(I)V"; + jint jnivalue = static_cast(cppValue.Raw()); + chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), jnivalue, + value); + return value; + } case Attributes::GeneratedCommandList::Id: { using TypeInfo = Attributes::GeneratedCommandList::TypeInfo; TypeInfo::DecodableType cppValue; diff --git a/src/controller/java/zap-generated/CHIPClientCallbacks.h b/src/controller/java/zap-generated/CHIPClientCallbacks.h index fdc34c7fee5595..4ba2a2d93b7451 100644 --- a/src/controller/java/zap-generated/CHIPClientCallbacks.h +++ b/src/controller/java/zap-generated/CHIPClientCallbacks.h @@ -713,13 +713,13 @@ typedef void (*ActivatedCarbonFilterMonitoringEventListListAttributeCallback)( void * context, const chip::app::DataModel::DecodableList & data); typedef void (*ActivatedCarbonFilterMonitoringAttributeListListAttributeCallback)( void * context, const chip::app::DataModel::DecodableList & data); -typedef void (*BooleanSensorConfigurationGeneratedCommandListListAttributeCallback)( +typedef void (*BooleanStateConfigurationGeneratedCommandListListAttributeCallback)( void * context, const chip::app::DataModel::DecodableList & data); -typedef void (*BooleanSensorConfigurationAcceptedCommandListListAttributeCallback)( +typedef void (*BooleanStateConfigurationAcceptedCommandListListAttributeCallback)( void * context, const chip::app::DataModel::DecodableList & data); -typedef void (*BooleanSensorConfigurationEventListListAttributeCallback)( +typedef void (*BooleanStateConfigurationEventListListAttributeCallback)( void * context, const chip::app::DataModel::DecodableList & data); -typedef void (*BooleanSensorConfigurationAttributeListListAttributeCallback)( +typedef void (*BooleanStateConfigurationAttributeListListAttributeCallback)( void * context, const chip::app::DataModel::DecodableList & data); typedef void (*ValveConfigurationAndControlGeneratedCommandListListAttributeCallback)( void * context, const chip::app::DataModel::DecodableList & data); diff --git a/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp b/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp index c8b407678f3d20..d5b8cec9d91b2f 100644 --- a/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp +++ b/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp @@ -3288,12 +3288,12 @@ JNI_METHOD(void, ActivatedCarbonFilterMonitoringCluster, writeLastChangedTimeAtt onFailure.release(); } -JNI_METHOD(void, BooleanSensorConfigurationCluster, writeSensitivityLevelAttribute) +JNI_METHOD(void, BooleanStateConfigurationCluster, writeCurrentSensitivityLevelAttribute) (JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, jobject value, jobject timedWriteTimeoutMs) { chip::DeviceLayer::StackLock lock; ListFreer listFreer; - using TypeInfo = chip::app::Clusters::BooleanSensorConfiguration::Attributes::SensitivityLevel::TypeInfo; + using TypeInfo = chip::app::Clusters::BooleanStateConfiguration::Attributes::CurrentSensitivityLevel::TypeInfo; TypeInfo::Type cppValue; std::vector> cleanupByteArrays; @@ -3314,60 +3314,8 @@ JNI_METHOD(void, BooleanSensorConfigurationCluster, writeSensitivityLevelAttribu chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( env, callback, "Error creating native failure callback", CHIP_ERROR_NO_MEMORY)); - CHIP_ERROR err = CHIP_NO_ERROR; - BooleanSensorConfigurationCluster * cppCluster = reinterpret_cast(clusterPtr); - VerifyOrReturn(cppCluster != nullptr, - chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( - env, callback, "Could not get native cluster", CHIP_ERROR_INCORRECT_STATE)); - - auto successFn = chip::Callback::Callback::FromCancelable(onSuccess->Cancel()); - auto failureFn = chip::Callback::Callback::FromCancelable(onFailure->Cancel()); - - if (timedWriteTimeoutMs == nullptr) - { - err = cppCluster->WriteAttribute(cppValue, onSuccess->mContext, successFn->mCall, failureFn->mCall); - } - else - { - err = cppCluster->WriteAttribute(cppValue, onSuccess->mContext, successFn->mCall, failureFn->mCall, - chip::JniReferences::GetInstance().IntegerToPrimitive(timedWriteTimeoutMs)); - } - VerifyOrReturn( - err == CHIP_NO_ERROR, - chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error writing attribute", err)); - - onSuccess.release(); - onFailure.release(); -} - -JNI_METHOD(void, BooleanSensorConfigurationCluster, writeAlarmsEnabledAttribute) -(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, jobject value, jobject timedWriteTimeoutMs) -{ - chip::DeviceLayer::StackLock lock; - ListFreer listFreer; - using TypeInfo = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AlarmsEnabled::TypeInfo; - TypeInfo::Type cppValue; - - std::vector> cleanupByteArrays; - std::vector> cleanupStrings; - - cppValue.SetRaw(static_cast::IntegerType>( - chip::JniReferences::GetInstance().IntegerToPrimitive(value))); - - std::unique_ptr onSuccess( - Platform::New(callback), Platform::Delete); - VerifyOrReturn(onSuccess.get() != nullptr, - chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( - env, callback, "Error creating native success callback", CHIP_ERROR_NO_MEMORY)); - - std::unique_ptr onFailure( - Platform::New(callback), Platform::Delete); - VerifyOrReturn(onFailure.get() != nullptr, - chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( - env, callback, "Error creating native failure callback", CHIP_ERROR_NO_MEMORY)); - - CHIP_ERROR err = CHIP_NO_ERROR; - BooleanSensorConfigurationCluster * cppCluster = reinterpret_cast(clusterPtr); + CHIP_ERROR err = CHIP_NO_ERROR; + BooleanStateConfigurationCluster * cppCluster = reinterpret_cast(clusterPtr); VerifyOrReturn(cppCluster != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( env, callback, "Could not get native cluster", CHIP_ERROR_INCORRECT_STATE)); diff --git a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp index 6e3b2093ead51c..997cccac866bde 100644 --- a/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPEventTLVValueDecoder.cpp @@ -3663,8 +3663,8 @@ jobject DecodeEventValue(const app::ConcreteEventPath & aPath, TLV::TLVReader & } break; } - case app::Clusters::BooleanSensorConfiguration::Id: { - using namespace app::Clusters::BooleanSensorConfiguration; + case app::Clusters::BooleanStateConfiguration::Id: { + using namespace app::Clusters::BooleanStateConfiguration; switch (aPath.mEventId) { case Events::AlarmsStateChanged::Id: { @@ -3702,19 +3702,19 @@ jobject DecodeEventValue(const app::ConcreteEventPath & aPath, TLV::TLVReader & jclass alarmsStateChangedStructClass; err = chip::JniReferences::GetInstance().GetClassRef( - env, "chip/devicecontroller/ChipEventStructs$BooleanSensorConfigurationClusterAlarmsStateChangedEvent", + env, "chip/devicecontroller/ChipEventStructs$BooleanStateConfigurationClusterAlarmsStateChangedEvent", alarmsStateChangedStructClass); if (err != CHIP_NO_ERROR) { - ChipLogError(Zcl, "Could not find class ChipEventStructs$BooleanSensorConfigurationClusterAlarmsStateChangedEvent"); + ChipLogError(Zcl, "Could not find class ChipEventStructs$BooleanStateConfigurationClusterAlarmsStateChangedEvent"); return nullptr; } jmethodID alarmsStateChangedStructCtor = env->GetMethodID(alarmsStateChangedStructClass, "", "(Ljava/lang/Integer;Ljava/util/Optional;)V"); if (alarmsStateChangedStructCtor == nullptr) { - ChipLogError( - Zcl, "Could not find ChipEventStructs$BooleanSensorConfigurationClusterAlarmsStateChangedEvent constructor"); + ChipLogError(Zcl, + "Could not find ChipEventStructs$BooleanStateConfigurationClusterAlarmsStateChangedEvent constructor"); return nullptr; } @@ -3730,23 +3730,31 @@ jobject DecodeEventValue(const app::ConcreteEventPath & aPath, TLV::TLVReader & { return nullptr; } + jobject value_sensorFault; + std::string value_sensorFaultClassName = "java/lang/Integer"; + std::string value_sensorFaultCtorSignature = "(I)V"; + jint jnivalue_sensorFault = static_cast(cppValue.sensorFault.Raw()); + chip::JniReferences::GetInstance().CreateBoxedObject(value_sensorFaultClassName.c_str(), + value_sensorFaultCtorSignature.c_str(), jnivalue_sensorFault, + value_sensorFault); + jclass sensorFaultStructClass; err = chip::JniReferences::GetInstance().GetClassRef( - env, "chip/devicecontroller/ChipEventStructs$BooleanSensorConfigurationClusterSensorFaultEvent", + env, "chip/devicecontroller/ChipEventStructs$BooleanStateConfigurationClusterSensorFaultEvent", sensorFaultStructClass); if (err != CHIP_NO_ERROR) { - ChipLogError(Zcl, "Could not find class ChipEventStructs$BooleanSensorConfigurationClusterSensorFaultEvent"); + ChipLogError(Zcl, "Could not find class ChipEventStructs$BooleanStateConfigurationClusterSensorFaultEvent"); return nullptr; } - jmethodID sensorFaultStructCtor = env->GetMethodID(sensorFaultStructClass, "", "()V"); + jmethodID sensorFaultStructCtor = env->GetMethodID(sensorFaultStructClass, "", "(Ljava/lang/Integer;)V"); if (sensorFaultStructCtor == nullptr) { - ChipLogError(Zcl, "Could not find ChipEventStructs$BooleanSensorConfigurationClusterSensorFaultEvent constructor"); + ChipLogError(Zcl, "Could not find ChipEventStructs$BooleanStateConfigurationClusterSensorFaultEvent constructor"); return nullptr; } - jobject value = env->NewObject(sensorFaultStructClass, sensorFaultStructCtor); + jobject value = env->NewObject(sensorFaultStructClass, sensorFaultStructCtor, value_sensorFault); return value; } diff --git a/src/controller/java/zap-generated/CHIPReadCallbacks.cpp b/src/controller/java/zap-generated/CHIPReadCallbacks.cpp index e7d797ce9f0e92..f2c06db10fea72 100644 --- a/src/controller/java/zap-generated/CHIPReadCallbacks.cpp +++ b/src/controller/java/zap-generated/CHIPReadCallbacks.cpp @@ -29723,9 +29723,9 @@ void CHIPActivatedCarbonFilterMonitoringAttributeListAttributeCallback::Callback env->CallVoidMethod(javaCallbackRef, javaMethod, arrayListObj); } -CHIPBooleanSensorConfigurationGeneratedCommandListAttributeCallback:: -CHIPBooleanSensorConfigurationGeneratedCommandListAttributeCallback(jobject javaCallback, bool keepAlive) : - chip::Callback::Callback(CallbackFn, this), +CHIPBooleanStateConfigurationGeneratedCommandListAttributeCallback:: +CHIPBooleanStateConfigurationGeneratedCommandListAttributeCallback(jobject javaCallback, bool keepAlive) : + chip::Callback::Callback(CallbackFn, this), keepAlive(keepAlive) { JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -29742,8 +29742,8 @@ CHIPBooleanSensorConfigurationGeneratedCommandListAttributeCallback(jobject java } } -CHIPBooleanSensorConfigurationGeneratedCommandListAttributeCallback::~ -CHIPBooleanSensorConfigurationGeneratedCommandListAttributeCallback() +CHIPBooleanStateConfigurationGeneratedCommandListAttributeCallback::~ +CHIPBooleanStateConfigurationGeneratedCommandListAttributeCallback() { JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); if (env == nullptr) @@ -29754,7 +29754,7 @@ CHIPBooleanSensorConfigurationGeneratedCommandListAttributeCallback() env->DeleteGlobalRef(javaCallbackRef); } -void CHIPBooleanSensorConfigurationGeneratedCommandListAttributeCallback::CallbackFn( +void CHIPBooleanStateConfigurationGeneratedCommandListAttributeCallback::CallbackFn( void * context, const chip::app::DataModel::DecodableList & list) { chip::DeviceLayer::StackUnlock unlock; @@ -29764,8 +29764,8 @@ void CHIPBooleanSensorConfigurationGeneratedCommandListAttributeCallback::Callba VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNI env")); - std::unique_ptr cppCallback( - reinterpret_cast(context), maybeDestroy); + std::unique_ptr cppCallback( + reinterpret_cast(context), maybeDestroy); // It's valid for javaCallbackRef to be nullptr if the Java code passed in a null callback. javaCallbackRef = cppCallback.get()->javaCallbackRef; @@ -29796,9 +29796,9 @@ void CHIPBooleanSensorConfigurationGeneratedCommandListAttributeCallback::Callba env->CallVoidMethod(javaCallbackRef, javaMethod, arrayListObj); } -CHIPBooleanSensorConfigurationAcceptedCommandListAttributeCallback:: -CHIPBooleanSensorConfigurationAcceptedCommandListAttributeCallback(jobject javaCallback, bool keepAlive) : - chip::Callback::Callback(CallbackFn, this), +CHIPBooleanStateConfigurationAcceptedCommandListAttributeCallback:: +CHIPBooleanStateConfigurationAcceptedCommandListAttributeCallback(jobject javaCallback, bool keepAlive) : + chip::Callback::Callback(CallbackFn, this), keepAlive(keepAlive) { JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -29815,8 +29815,8 @@ CHIPBooleanSensorConfigurationAcceptedCommandListAttributeCallback(jobject javaC } } -CHIPBooleanSensorConfigurationAcceptedCommandListAttributeCallback::~ -CHIPBooleanSensorConfigurationAcceptedCommandListAttributeCallback() +CHIPBooleanStateConfigurationAcceptedCommandListAttributeCallback::~ +CHIPBooleanStateConfigurationAcceptedCommandListAttributeCallback() { JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); if (env == nullptr) @@ -29827,7 +29827,7 @@ CHIPBooleanSensorConfigurationAcceptedCommandListAttributeCallback() env->DeleteGlobalRef(javaCallbackRef); } -void CHIPBooleanSensorConfigurationAcceptedCommandListAttributeCallback::CallbackFn( +void CHIPBooleanStateConfigurationAcceptedCommandListAttributeCallback::CallbackFn( void * context, const chip::app::DataModel::DecodableList & list) { chip::DeviceLayer::StackUnlock unlock; @@ -29837,8 +29837,8 @@ void CHIPBooleanSensorConfigurationAcceptedCommandListAttributeCallback::Callbac VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNI env")); - std::unique_ptr cppCallback( - reinterpret_cast(context), maybeDestroy); + std::unique_ptr cppCallback( + reinterpret_cast(context), maybeDestroy); // It's valid for javaCallbackRef to be nullptr if the Java code passed in a null callback. javaCallbackRef = cppCallback.get()->javaCallbackRef; @@ -29869,9 +29869,9 @@ void CHIPBooleanSensorConfigurationAcceptedCommandListAttributeCallback::Callbac env->CallVoidMethod(javaCallbackRef, javaMethod, arrayListObj); } -CHIPBooleanSensorConfigurationEventListAttributeCallback::CHIPBooleanSensorConfigurationEventListAttributeCallback( +CHIPBooleanStateConfigurationEventListAttributeCallback::CHIPBooleanStateConfigurationEventListAttributeCallback( jobject javaCallback, bool keepAlive) : - chip::Callback::Callback(CallbackFn, this), + chip::Callback::Callback(CallbackFn, this), keepAlive(keepAlive) { JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -29888,7 +29888,7 @@ CHIPBooleanSensorConfigurationEventListAttributeCallback::CHIPBooleanSensorConfi } } -CHIPBooleanSensorConfigurationEventListAttributeCallback::~CHIPBooleanSensorConfigurationEventListAttributeCallback() +CHIPBooleanStateConfigurationEventListAttributeCallback::~CHIPBooleanStateConfigurationEventListAttributeCallback() { JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); if (env == nullptr) @@ -29899,7 +29899,7 @@ CHIPBooleanSensorConfigurationEventListAttributeCallback::~CHIPBooleanSensorConf env->DeleteGlobalRef(javaCallbackRef); } -void CHIPBooleanSensorConfigurationEventListAttributeCallback::CallbackFn( +void CHIPBooleanStateConfigurationEventListAttributeCallback::CallbackFn( void * context, const chip::app::DataModel::DecodableList & list) { chip::DeviceLayer::StackUnlock unlock; @@ -29909,8 +29909,8 @@ void CHIPBooleanSensorConfigurationEventListAttributeCallback::CallbackFn( VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNI env")); - std::unique_ptr cppCallback( - reinterpret_cast(context), maybeDestroy); + std::unique_ptr cppCallback( + reinterpret_cast(context), maybeDestroy); // It's valid for javaCallbackRef to be nullptr if the Java code passed in a null callback. javaCallbackRef = cppCallback.get()->javaCallbackRef; @@ -29941,9 +29941,9 @@ void CHIPBooleanSensorConfigurationEventListAttributeCallback::CallbackFn( env->CallVoidMethod(javaCallbackRef, javaMethod, arrayListObj); } -CHIPBooleanSensorConfigurationAttributeListAttributeCallback::CHIPBooleanSensorConfigurationAttributeListAttributeCallback( +CHIPBooleanStateConfigurationAttributeListAttributeCallback::CHIPBooleanStateConfigurationAttributeListAttributeCallback( jobject javaCallback, bool keepAlive) : - chip::Callback::Callback(CallbackFn, this), + chip::Callback::Callback(CallbackFn, this), keepAlive(keepAlive) { JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -29960,7 +29960,7 @@ CHIPBooleanSensorConfigurationAttributeListAttributeCallback::CHIPBooleanSensorC } } -CHIPBooleanSensorConfigurationAttributeListAttributeCallback::~CHIPBooleanSensorConfigurationAttributeListAttributeCallback() +CHIPBooleanStateConfigurationAttributeListAttributeCallback::~CHIPBooleanStateConfigurationAttributeListAttributeCallback() { JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); if (env == nullptr) @@ -29971,7 +29971,7 @@ CHIPBooleanSensorConfigurationAttributeListAttributeCallback::~CHIPBooleanSensor env->DeleteGlobalRef(javaCallbackRef); } -void CHIPBooleanSensorConfigurationAttributeListAttributeCallback::CallbackFn( +void CHIPBooleanStateConfigurationAttributeListAttributeCallback::CallbackFn( void * context, const chip::app::DataModel::DecodableList & list) { chip::DeviceLayer::StackUnlock unlock; @@ -29981,8 +29981,8 @@ void CHIPBooleanSensorConfigurationAttributeListAttributeCallback::CallbackFn( VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNI env")); - std::unique_ptr cppCallback( - reinterpret_cast(context), maybeDestroy); + std::unique_ptr cppCallback( + reinterpret_cast(context), maybeDestroy); // It's valid for javaCallbackRef to be nullptr if the Java code passed in a null callback. javaCallbackRef = cppCallback.get()->javaCallbackRef; diff --git a/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java b/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java index 99db5abbfecc9f..5f4c1939a70cb6 100644 --- a/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/zap-generated/chip/devicecontroller/ChipClusters.java @@ -18114,10 +18114,10 @@ private native void subscribeClusterRevisionAttribute(long chipClusterPtr, , int minInterval, int maxInterval); } - public static class BooleanSensorConfigurationCluster extends BaseChipCluster { + public static class BooleanStateConfigurationCluster extends BaseChipCluster { public static final long CLUSTER_ID = 0x00000080L; - public BooleanSensorConfigurationCluster(long devicePtr, int endpointId) { + public BooleanStateConfigurationCluster(long devicePtr, int endpointId) { super(devicePtr, endpointId); } @@ -40489,4 +40489,3 @@ private native void subscribeClusterRevisionAttribute(long chipClusterPtr, , int minInterval, int maxInterval); } } - diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index e6a384cd3336a9..08ff2ab1b8d93a 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -6135,44 +6135,74 @@ class ChipClusters: }, }, } - _BOOLEAN_SENSOR_CONFIGURATION_CLUSTER_INFO = { - "clusterName": "BooleanSensorConfiguration", + _BOOLEAN_STATE_CONFIGURATION_CLUSTER_INFO = { + "clusterName": "BooleanStateConfiguration", "clusterId": 0x00000080, "commands": { 0x00000000: { "commandId": 0x00000000, - "commandName": "SuppressRequest", + "commandName": "SuppressAlarm", "args": { "alarmsToSuppress": "int", }, }, + 0x00000001: { + "commandId": 0x00000001, + "commandName": "EnableDisableAlarm", + "args": { + "alarmsToEnableDisable": "int", + }, + }, }, "attributes": { 0x00000000: { - "attributeName": "SensitivityLevel", + "attributeName": "CurrentSensitivityLevel", "attributeId": 0x00000000, "type": "int", "reportable": True, "writable": True, }, 0x00000001: { - "attributeName": "AlarmsActive", + "attributeName": "SupportedSensitivityLevels", "attributeId": 0x00000001, "type": "int", "reportable": True, }, 0x00000002: { - "attributeName": "AlarmsSuppressed", + "attributeName": "DefaultSensitivityLevel", "attributeId": 0x00000002, "type": "int", "reportable": True, }, 0x00000003: { - "attributeName": "AlarmsEnabled", + "attributeName": "AlarmsActive", "attributeId": 0x00000003, "type": "int", "reportable": True, - "writable": True, + }, + 0x00000004: { + "attributeName": "AlarmsSuppressed", + "attributeId": 0x00000004, + "type": "int", + "reportable": True, + }, + 0x00000005: { + "attributeName": "AlarmsEnabled", + "attributeId": 0x00000005, + "type": "int", + "reportable": True, + }, + 0x00000006: { + "attributeName": "AlarmsSupported", + "attributeId": 0x00000006, + "type": "int", + "reportable": True, + }, + 0x00000007: { + "attributeName": "SensorFault", + "attributeId": 0x00000007, + "type": "int", + "reportable": True, }, 0x0000FFF8: { "attributeName": "GeneratedCommandList", @@ -13836,7 +13866,7 @@ class ChipClusters: 0x00000061: _RVC_OPERATIONAL_STATE_CLUSTER_INFO, 0x00000071: _HEPA_FILTER_MONITORING_CLUSTER_INFO, 0x00000072: _ACTIVATED_CARBON_FILTER_MONITORING_CLUSTER_INFO, - 0x00000080: _BOOLEAN_SENSOR_CONFIGURATION_CLUSTER_INFO, + 0x00000080: _BOOLEAN_STATE_CONFIGURATION_CLUSTER_INFO, 0x00000081: _VALVE_CONFIGURATION_AND_CONTROL_CLUSTER_INFO, 0x00000091: _ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER_INFO, 0x00000096: _DEMAND_RESPONSE_LOAD_CONTROL_CLUSTER_INFO, @@ -13951,7 +13981,7 @@ class ChipClusters: "RvcOperationalState": _RVC_OPERATIONAL_STATE_CLUSTER_INFO, "HepaFilterMonitoring": _HEPA_FILTER_MONITORING_CLUSTER_INFO, "ActivatedCarbonFilterMonitoring": _ACTIVATED_CARBON_FILTER_MONITORING_CLUSTER_INFO, - "BooleanSensorConfiguration": _BOOLEAN_SENSOR_CONFIGURATION_CLUSTER_INFO, + "BooleanStateConfiguration": _BOOLEAN_STATE_CONFIGURATION_CLUSTER_INFO, "ValveConfigurationAndControl": _VALVE_CONFIGURATION_AND_CONTROL_CLUSTER_INFO, "ElectricalEnergyMeasurement": _ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER_INFO, "DemandResponseLoadControl": _DEMAND_RESPONSE_LOAD_CONTROL_CLUSTER_INFO, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 5fd82a3382a339..4e103ede217200 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -21483,17 +21483,21 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: @dataclass -class BooleanSensorConfiguration(Cluster): +class BooleanStateConfiguration(Cluster): id: typing.ClassVar[int] = 0x00000080 @ChipUtility.classproperty def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="sensitivityLevel", Tag=0x00000000, Type=typing.Optional[BooleanSensorConfiguration.Enums.SensitivityEnum]), - ClusterObjectFieldDescriptor(Label="alarmsActive", Tag=0x00000001, Type=typing.Optional[uint]), - ClusterObjectFieldDescriptor(Label="alarmsSuppressed", Tag=0x00000002, Type=typing.Optional[uint]), - ClusterObjectFieldDescriptor(Label="alarmsEnabled", Tag=0x00000003, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="currentSensitivityLevel", Tag=0x00000000, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="supportedSensitivityLevels", Tag=0x00000001, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="defaultSensitivityLevel", Tag=0x00000002, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="alarmsActive", Tag=0x00000003, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="alarmsSuppressed", Tag=0x00000004, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="alarmsEnabled", Tag=0x00000005, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="alarmsSupported", Tag=0x00000006, Type=typing.Optional[uint]), + ClusterObjectFieldDescriptor(Label="sensorFault", Tag=0x00000007, Type=typing.Optional[uint]), ClusterObjectFieldDescriptor(Label="generatedCommandList", Tag=0x0000FFF8, Type=typing.List[uint]), ClusterObjectFieldDescriptor(Label="acceptedCommandList", Tag=0x0000FFF9, Type=typing.List[uint]), ClusterObjectFieldDescriptor(Label="eventList", Tag=0x0000FFFA, Type=typing.List[uint]), @@ -21502,10 +21506,14 @@ def descriptor(cls) -> ClusterObjectDescriptor: ClusterObjectFieldDescriptor(Label="clusterRevision", Tag=0x0000FFFD, Type=uint), ]) - sensitivityLevel: 'typing.Optional[BooleanSensorConfiguration.Enums.SensitivityEnum]' = None + currentSensitivityLevel: 'typing.Optional[uint]' = None + supportedSensitivityLevels: 'typing.Optional[uint]' = None + defaultSensitivityLevel: 'typing.Optional[uint]' = None alarmsActive: 'typing.Optional[uint]' = None alarmsSuppressed: 'typing.Optional[uint]' = None alarmsEnabled: 'typing.Optional[uint]' = None + alarmsSupported: 'typing.Optional[uint]' = None + sensorFault: 'typing.Optional[uint]' = None generatedCommandList: 'typing.List[uint]' = None acceptedCommandList: 'typing.List[uint]' = None eventList: 'typing.List[uint]' = None @@ -21513,17 +21521,6 @@ def descriptor(cls) -> ClusterObjectDescriptor: featureMap: 'uint' = None clusterRevision: 'uint' = None - class Enums: - class SensitivityEnum(MatterIntEnum): - kHigh = 0x00 - kStandard = 0x01 - kLow = 0x02 - # All received enum values that are not listed above will be mapped - # to kUnknownEnumValue. This is a helper enum value that should only - # be used by code to process how it handles receiving and unknown - # enum value. This specific should never be transmitted. - kUnknownEnumValue = 3, - class Bitmaps: class AlarmModeBitmap(IntFlag): kVisual = 0x1 @@ -21535,9 +21532,12 @@ class Feature(IntFlag): kAlarmSuppress = 0x4 kSensitivityLevel = 0x8 + class SensorFaultBitmap(IntFlag): + kGeneralFault = 0x1 + class Commands: @dataclass - class SuppressRequest(ClusterCommand): + class SuppressAlarm(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x00000080 command_id: typing.ClassVar[int] = 0x00000000 is_client: typing.ClassVar[bool] = True @@ -21552,9 +21552,25 @@ def descriptor(cls) -> ClusterObjectDescriptor: alarmsToSuppress: 'uint' = 0 + @dataclass + class EnableDisableAlarm(ClusterCommand): + cluster_id: typing.ClassVar[int] = 0x00000080 + command_id: typing.ClassVar[int] = 0x00000001 + is_client: typing.ClassVar[bool] = True + response_type: typing.ClassVar[str] = None + + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="alarmsToEnableDisable", Tag=0, Type=uint), + ]) + + alarmsToEnableDisable: 'uint' = 0 + class Attributes: @dataclass - class SensitivityLevel(ClusterAttributeDescriptor): + class CurrentSensitivityLevel(ClusterAttributeDescriptor): @ChipUtility.classproperty def cluster_id(cls) -> int: return 0x00000080 @@ -21565,12 +21581,12 @@ def attribute_id(cls) -> int: @ChipUtility.classproperty def attribute_type(cls) -> ClusterObjectFieldDescriptor: - return ClusterObjectFieldDescriptor(Type=typing.Optional[BooleanSensorConfiguration.Enums.SensitivityEnum]) + return ClusterObjectFieldDescriptor(Type=typing.Optional[uint]) - value: 'typing.Optional[BooleanSensorConfiguration.Enums.SensitivityEnum]' = None + value: 'typing.Optional[uint]' = None @dataclass - class AlarmsActive(ClusterAttributeDescriptor): + class SupportedSensitivityLevels(ClusterAttributeDescriptor): @ChipUtility.classproperty def cluster_id(cls) -> int: return 0x00000080 @@ -21586,7 +21602,7 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'typing.Optional[uint]' = None @dataclass - class AlarmsSuppressed(ClusterAttributeDescriptor): + class DefaultSensitivityLevel(ClusterAttributeDescriptor): @ChipUtility.classproperty def cluster_id(cls) -> int: return 0x00000080 @@ -21602,7 +21618,7 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'typing.Optional[uint]' = None @dataclass - class AlarmsEnabled(ClusterAttributeDescriptor): + class AlarmsActive(ClusterAttributeDescriptor): @ChipUtility.classproperty def cluster_id(cls) -> int: return 0x00000080 @@ -21617,6 +21633,70 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'typing.Optional[uint]' = None + @dataclass + class AlarmsSuppressed(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000080 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x00000004 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.Optional[uint]) + + value: 'typing.Optional[uint]' = None + + @dataclass + class AlarmsEnabled(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000080 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x00000005 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.Optional[uint]) + + value: 'typing.Optional[uint]' = None + + @dataclass + class AlarmsSupported(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000080 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x00000006 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.Optional[uint]) + + value: 'typing.Optional[uint]' = None + + @dataclass + class SensorFault(ClusterAttributeDescriptor): + @ChipUtility.classproperty + def cluster_id(cls) -> int: + return 0x00000080 + + @ChipUtility.classproperty + def attribute_id(cls) -> int: + return 0x00000007 + + @ChipUtility.classproperty + def attribute_type(cls) -> ClusterObjectFieldDescriptor: + return ClusterObjectFieldDescriptor(Type=typing.Optional[uint]) + + value: 'typing.Optional[uint]' = None + @dataclass class GeneratedCommandList(ClusterAttributeDescriptor): @ChipUtility.classproperty @@ -21749,8 +21829,11 @@ def event_id(cls) -> int: def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ + ClusterObjectFieldDescriptor(Label="sensorFault", Tag=0, Type=uint), ]) + sensorFault: 'uint' = 0 + @dataclass class ValveConfigurationAndControl(Cluster): diff --git a/src/controller/python/chip/clusters/__init__.py b/src/controller/python/chip/clusters/__init__.py index 04644cb5a4d109..3a6099961c0463 100644 --- a/src/controller/python/chip/clusters/__init__.py +++ b/src/controller/python/chip/clusters/__init__.py @@ -25,7 +25,7 @@ from . import Attribute, CHIPClusters, Command from .Objects import (AccessControl, AccountLogin, Actions, ActivatedCarbonFilterMonitoring, AdministratorCommissioning, AirQuality, ApplicationBasic, ApplicationLauncher, AudioOutput, BallastConfiguration, BarrierControl, BasicInformation, - BinaryInputBasic, Binding, BooleanSensorConfiguration, BooleanState, BridgedDeviceBasicInformation, + BinaryInputBasic, Binding, BooleanState, BooleanStateConfiguration, BridgedDeviceBasicInformation, CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, Channel, ColorControl, ContentLauncher, Descriptor, DeviceEnergyManagement, DiagnosticLogs, DishwasherAlarm, DishwasherMode, DoorLock, ElectricalMeasurement, EnergyEvse, EthernetNetworkDiagnostics, FanControl, FaultInjection, @@ -47,7 +47,7 @@ __all__ = [Attribute, CHIPClusters, Command, AccessControl, AccountLogin, Actions, ActivatedCarbonFilterMonitoring, AdministratorCommissioning, AirQuality, ApplicationBasic, ApplicationLauncher, AudioOutput, BallastConfiguration, BarrierControl, BasicInformation, - BinaryInputBasic, Binding, BooleanSensorConfiguration, BooleanState, BridgedDeviceBasicInformation, CarbonDioxideConcentrationMeasurement, + BinaryInputBasic, Binding, BooleanStateConfiguration, BooleanState, BridgedDeviceBasicInformation, CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, Channel, ColorControl, ContentLauncher, Descriptor, DeviceEnergyManagement, DiagnosticLogs, DishwasherAlarm, DishwasherMode, DoorLock, ElectricalMeasurement, EnergyEvse, EthernetNetworkDiagnostics, FanControl, FaultInjection, FixedLabel, FlowMeasurement, diff --git a/src/darwin/Framework/CHIP/templates/availability.yaml b/src/darwin/Framework/CHIP/templates/availability.yaml index 2558acd871a30e..935a3889eea738 100644 --- a/src/darwin/Framework/CHIP/templates/availability.yaml +++ b/src/darwin/Framework/CHIP/templates/availability.yaml @@ -8249,7 +8249,7 @@ - MicrowaveOvenControl - MicrowaveOvenMode - DemandResponseLoadControl - - BooleanSensorConfiguration + - BooleanStateConfiguration - ValveConfigurationAndControl - Timer - OvenMode diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm index 1f7d91156734b9..d579533e2eb296 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm @@ -2819,11 +2819,17 @@ static BOOL AttributeIsSpecifiedInActivatedCarbonFilterMonitoringCluster(Attribu } } } -static BOOL AttributeIsSpecifiedInBooleanSensorConfigurationCluster(AttributeId aAttributeId) +static BOOL AttributeIsSpecifiedInBooleanStateConfigurationCluster(AttributeId aAttributeId) { - using namespace Clusters::BooleanSensorConfiguration; + using namespace Clusters::BooleanStateConfiguration; switch (aAttributeId) { - case Attributes::SensitivityLevel::Id: { + case Attributes::CurrentSensitivityLevel::Id: { + return YES; + } + case Attributes::SupportedSensitivityLevels::Id: { + return YES; + } + case Attributes::DefaultSensitivityLevel::Id: { return YES; } case Attributes::AlarmsActive::Id: { @@ -2835,6 +2841,12 @@ static BOOL AttributeIsSpecifiedInBooleanSensorConfigurationCluster(AttributeId case Attributes::AlarmsEnabled::Id: { return YES; } + case Attributes::AlarmsSupported::Id: { + return YES; + } + case Attributes::SensorFault::Id: { + return YES; + } case Attributes::GeneratedCommandList::Id: { return YES; } @@ -6342,8 +6354,8 @@ BOOL MTRAttributeIsSpecified(ClusterId aClusterId, AttributeId aAttributeId) case Clusters::ActivatedCarbonFilterMonitoring::Id: { return AttributeIsSpecifiedInActivatedCarbonFilterMonitoringCluster(aAttributeId); } - case Clusters::BooleanSensorConfiguration::Id: { - return AttributeIsSpecifiedInBooleanSensorConfigurationCluster(aAttributeId); + case Clusters::BooleanStateConfiguration::Id: { + return AttributeIsSpecifiedInBooleanStateConfigurationCluster(aAttributeId); } case Clusters::ValveConfigurationAndControl::Id: { return AttributeIsSpecifiedInValveConfigurationAndControlCluster(aAttributeId); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm index 25d41e9c8bf966..5910c74a60e412 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm @@ -7381,19 +7381,41 @@ static id _Nullable DecodeAttributeValueForActivatedCarbonFilterMonitoringCluste *aError = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB; return nil; } -static id _Nullable DecodeAttributeValueForBooleanSensorConfigurationCluster(AttributeId aAttributeId, TLV::TLVReader & aReader, CHIP_ERROR * aError) +static id _Nullable DecodeAttributeValueForBooleanStateConfigurationCluster(AttributeId aAttributeId, TLV::TLVReader & aReader, CHIP_ERROR * aError) { - using namespace Clusters::BooleanSensorConfiguration; + using namespace Clusters::BooleanStateConfiguration; switch (aAttributeId) { - case Attributes::SensitivityLevel::Id: { - using TypeInfo = Attributes::SensitivityLevel::TypeInfo; + case Attributes::CurrentSensitivityLevel::Id: { + using TypeInfo = Attributes::CurrentSensitivityLevel::TypeInfo; TypeInfo::DecodableType cppValue; *aError = DataModel::Decode(aReader, cppValue); if (*aError != CHIP_NO_ERROR) { return nil; } NSNumber * _Nonnull value; - value = [NSNumber numberWithUnsignedChar:chip::to_underlying(cppValue)]; + value = [NSNumber numberWithUnsignedChar:cppValue]; + return value; + } + case Attributes::SupportedSensitivityLevels::Id: { + using TypeInfo = Attributes::SupportedSensitivityLevels::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSNumber * _Nonnull value; + value = [NSNumber numberWithUnsignedChar:cppValue]; + return value; + } + case Attributes::DefaultSensitivityLevel::Id: { + using TypeInfo = Attributes::DefaultSensitivityLevel::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSNumber * _Nonnull value; + value = [NSNumber numberWithUnsignedChar:cppValue]; return value; } case Attributes::AlarmsActive::Id: { @@ -7429,6 +7451,28 @@ static id _Nullable DecodeAttributeValueForBooleanSensorConfigurationCluster(Att value = [NSNumber numberWithUnsignedChar:cppValue.Raw()]; return value; } + case Attributes::AlarmsSupported::Id: { + using TypeInfo = Attributes::AlarmsSupported::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSNumber * _Nonnull value; + value = [NSNumber numberWithUnsignedChar:cppValue.Raw()]; + return value; + } + case Attributes::SensorFault::Id: { + using TypeInfo = Attributes::SensorFault::TypeInfo; + TypeInfo::DecodableType cppValue; + *aError = DataModel::Decode(aReader, cppValue); + if (*aError != CHIP_NO_ERROR) { + return nil; + } + NSNumber * _Nonnull value; + value = [NSNumber numberWithUnsignedShort:cppValue.Raw()]; + return value; + } default: { break; } @@ -17904,8 +17948,8 @@ id _Nullable MTRDecodeAttributeValue(const ConcreteAttributePath & aPath, TLV::T case Clusters::ActivatedCarbonFilterMonitoring::Id: { return DecodeAttributeValueForActivatedCarbonFilterMonitoringCluster(aPath.mAttributeId, aReader, aError); } - case Clusters::BooleanSensorConfiguration::Id: { - return DecodeAttributeValueForBooleanSensorConfigurationCluster(aPath.mAttributeId, aReader, aError); + case Clusters::BooleanStateConfiguration::Id: { + return DecodeAttributeValueForBooleanStateConfigurationCluster(aPath.mAttributeId, aReader, aError); } case Clusters::ValveConfigurationAndControl::Id: { return DecodeAttributeValueForValveConfigurationAndControlCluster(aPath.mAttributeId, aReader, aError); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 0bfb44111478a2..23f78925c5f2e1 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -6985,27 +6985,45 @@ MTR_PROVISIONALLY_AVAILABLE @end /** - * Cluster Boolean Sensor Configuration + * Cluster Boolean State Configuration * * This cluster is used to configure a boolean sensor. */ MTR_PROVISIONALLY_AVAILABLE -@interface MTRBaseClusterBooleanSensorConfiguration : MTRGenericBaseCluster +@interface MTRBaseClusterBooleanStateConfiguration : MTRGenericBaseCluster /** - * Command SuppressRequest + * Command SuppressAlarm * - * This command is used to suppress the specified alarm. + * This command is used to suppress the specified alarm mode. */ -- (void)suppressRequestWithParams:(MTRBooleanSensorConfigurationClusterSuppressRequestParams *)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)suppressAlarmWithParams:(MTRBooleanStateConfigurationClusterSuppressAlarmParams *)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +/** + * Command EnableDisableAlarm + * + * This command is used to enable or disable the specified alarm mode. + */ +- (void)enableDisableAlarmWithParams:(MTRBooleanStateConfigurationClusterEnableDisableAlarmParams *)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)readAttributeSensitivityLevelWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeSensitivityLevelWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeSensitivityLevelWithValue:(NSNumber * _Nonnull)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)subscribeAttributeSensitivityLevelWithParams:(MTRSubscribeParams *)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; -+ (void)readAttributeSensitivityLevelWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)readAttributeCurrentSensitivityLevelWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)writeAttributeCurrentSensitivityLevelWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)writeAttributeCurrentSensitivityLevelWithValue:(NSNumber * _Nonnull)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeCurrentSensitivityLevelWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeCurrentSensitivityLevelWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeSupportedSensitivityLevelsWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeSupportedSensitivityLevelsWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeSupportedSensitivityLevelsWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeDefaultSensitivityLevelWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeDefaultSensitivityLevelWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeDefaultSensitivityLevelWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)readAttributeAlarmsActiveWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)subscribeAttributeAlarmsActiveWithParams:(MTRSubscribeParams *)params @@ -7020,13 +7038,23 @@ MTR_PROVISIONALLY_AVAILABLE + (void)readAttributeAlarmsSuppressedWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)readAttributeAlarmsEnabledWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeAlarmsEnabledWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeAlarmsEnabledWithValue:(NSNumber * _Nonnull)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; - (void)subscribeAttributeAlarmsEnabledWithParams:(MTRSubscribeParams *)params subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; + (void)readAttributeAlarmsEnabledWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)readAttributeAlarmsSupportedWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeAlarmsSupportedWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeAlarmsSupportedWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + +- (void)readAttributeSensorFaultWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeSensorFaultWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeSensorFaultWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + - (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams *)params subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished @@ -7068,7 +7096,7 @@ MTR_PROVISIONALLY_AVAILABLE @end -@interface MTRBaseClusterBooleanSensorConfiguration (Availability) +@interface MTRBaseClusterBooleanStateConfiguration (Availability) /** * For all instance methods (reads, writes, commands) that take a completion, @@ -16811,22 +16839,20 @@ typedef NS_OPTIONS(uint32_t, MTRActivatedCarbonFilterMonitoringFeature) { MTRActivatedCarbonFilterMonitoringFeatureReplacementProductList MTR_PROVISIONALLY_AVAILABLE = 0x4, } MTR_PROVISIONALLY_AVAILABLE; -typedef NS_ENUM(uint8_t, MTRBooleanSensorConfigurationSensitivity) { - MTRBooleanSensorConfigurationSensitivityHigh MTR_PROVISIONALLY_AVAILABLE = 0x00, - MTRBooleanSensorConfigurationSensitivityStandard MTR_PROVISIONALLY_AVAILABLE = 0x01, - MTRBooleanSensorConfigurationSensitivityLow MTR_PROVISIONALLY_AVAILABLE = 0x02, +typedef NS_OPTIONS(uint8_t, MTRBooleanStateConfigurationAlarmModeBitmap) { + MTRBooleanStateConfigurationAlarmModeBitmapVisual MTR_PROVISIONALLY_AVAILABLE = 0x1, + MTRBooleanStateConfigurationAlarmModeBitmapAudible MTR_PROVISIONALLY_AVAILABLE = 0x2, } MTR_PROVISIONALLY_AVAILABLE; -typedef NS_OPTIONS(uint8_t, MTRBooleanSensorConfigurationAlarmModeBitmap) { - MTRBooleanSensorConfigurationAlarmModeBitmapVisual MTR_PROVISIONALLY_AVAILABLE = 0x1, - MTRBooleanSensorConfigurationAlarmModeBitmapAudible MTR_PROVISIONALLY_AVAILABLE = 0x2, +typedef NS_OPTIONS(uint32_t, MTRBooleanStateConfigurationFeature) { + MTRBooleanStateConfigurationFeatureVisual MTR_PROVISIONALLY_AVAILABLE = 0x1, + MTRBooleanStateConfigurationFeatureAudible MTR_PROVISIONALLY_AVAILABLE = 0x2, + MTRBooleanStateConfigurationFeatureAlarmSuppress MTR_PROVISIONALLY_AVAILABLE = 0x4, + MTRBooleanStateConfigurationFeatureSensitivityLevel MTR_PROVISIONALLY_AVAILABLE = 0x8, } MTR_PROVISIONALLY_AVAILABLE; -typedef NS_OPTIONS(uint32_t, MTRBooleanSensorConfigurationFeature) { - MTRBooleanSensorConfigurationFeatureVisual MTR_PROVISIONALLY_AVAILABLE = 0x1, - MTRBooleanSensorConfigurationFeatureAudible MTR_PROVISIONALLY_AVAILABLE = 0x2, - MTRBooleanSensorConfigurationFeatureAlarmSuppress MTR_PROVISIONALLY_AVAILABLE = 0x4, - MTRBooleanSensorConfigurationFeatureSensitivityLevel MTR_PROVISIONALLY_AVAILABLE = 0x8, +typedef NS_OPTIONS(uint16_t, MTRBooleanStateConfigurationSensorFaultBitmap) { + MTRBooleanStateConfigurationSensorFaultBitmapGeneralFault MTR_PROVISIONALLY_AVAILABLE = 0x1, } MTR_PROVISIONALLY_AVAILABLE; typedef NS_ENUM(uint8_t, MTRValveConfigurationAndControlValveState) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index 45c8b38f7a85dc..a302e645ffec6a 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -49082,12 +49082,12 @@ + (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheC @end -@implementation MTRBaseClusterBooleanSensorConfiguration +@implementation MTRBaseClusterBooleanStateConfiguration -- (void)suppressRequestWithParams:(MTRBooleanSensorConfigurationClusterSuppressRequestParams *)params completion:(MTRStatusCompletion)completion +- (void)suppressAlarmWithParams:(MTRBooleanStateConfigurationClusterSuppressAlarmParams *)params completion:(MTRStatusCompletion)completion { if (params == nil) { - params = [[MTRBooleanSensorConfigurationClusterSuppressRequestParams + params = [[MTRBooleanStateConfigurationClusterSuppressAlarmParams alloc] init]; } @@ -49097,7 +49097,31 @@ - (void)suppressRequestWithParams:(MTRBooleanSensorConfigurationClusterSuppressR auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - using RequestType = BooleanSensorConfiguration::Commands::SuppressRequest::Type; + using RequestType = BooleanStateConfiguration::Commands::SuppressAlarm::Type; + [self.device _invokeKnownCommandWithEndpointID:@(self.endpoint) + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.callbackQueue + completion:responseHandler]; +} +- (void)enableDisableAlarmWithParams:(MTRBooleanStateConfigurationClusterEnableDisableAlarmParams *)params completion:(MTRStatusCompletion)completion +{ + if (params == nil) { + params = [[MTRBooleanStateConfigurationClusterEnableDisableAlarmParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = BooleanStateConfiguration::Commands::EnableDisableAlarm::Type; [self.device _invokeKnownCommandWithEndpointID:@(self.endpoint) clusterID:@(RequestType::GetClusterId()) commandID:@(RequestType::GetCommandId()) @@ -49109,9 +49133,9 @@ - (void)suppressRequestWithParams:(MTRBooleanSensorConfigurationClusterSuppressR completion:responseHandler]; } -- (void)readAttributeSensitivityLevelWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +- (void)readAttributeCurrentSensitivityLevelWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::SensitivityLevel::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::CurrentSensitivityLevel::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49120,11 +49144,11 @@ - (void)readAttributeSensitivityLevelWithCompletion:(void (^)(NSNumber * _Nullab completion:completion]; } -- (void)writeAttributeSensitivityLevelWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion +- (void)writeAttributeCurrentSensitivityLevelWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion { - [self writeAttributeSensitivityLevelWithValue:(NSNumber * _Nonnull) value params:nil completion:completion]; + [self writeAttributeCurrentSensitivityLevelWithValue:(NSNumber * _Nonnull) value params:nil completion:completion]; } -- (void)writeAttributeSensitivityLevelWithValue:(NSNumber * _Nonnull)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion +- (void)writeAttributeCurrentSensitivityLevelWithValue:(NSNumber * _Nonnull)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion { // Make a copy of params before we go async. params = [params copy]; @@ -49139,20 +49163,56 @@ - (void)writeAttributeSensitivityLevelWithValue:(NSNumber * _Nonnull)value param } ListFreer listFreer; - using TypeInfo = BooleanSensorConfiguration::Attributes::SensitivityLevel::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::CurrentSensitivityLevel::TypeInfo; TypeInfo::Type cppValue; - cppValue = static_cast>(value.unsignedCharValue); + cppValue = value.unsignedCharValue; chip::Controller::ClusterBase cppCluster(exchangeManager, session, self.endpoint); return cppCluster.WriteAttribute(cppValue, bridge, successCb, failureCb, timedWriteTimeout); }); std::move(*bridge).DispatchAction(self.device); } -- (void)subscribeAttributeSensitivityLevelWithParams:(MTRSubscribeParams * _Nonnull)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +- (void)subscribeAttributeCurrentSensitivityLevelWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = BooleanStateConfiguration::Attributes::CurrentSensitivityLevel::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeCurrentSensitivityLevelWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = BooleanStateConfiguration::Attributes::CurrentSensitivityLevel::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeSupportedSensitivityLevelsWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::SensitivityLevel::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::SupportedSensitivityLevels::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeSupportedSensitivityLevelsWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = BooleanStateConfiguration::Attributes::SupportedSensitivityLevels::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49162,9 +49222,45 @@ - (void)subscribeAttributeSensitivityLevelWithParams:(MTRSubscribeParams * _Nonn subscriptionEstablished:subscriptionEstablished]; } -+ (void)readAttributeSensitivityLevelWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion ++ (void)readAttributeSupportedSensitivityLevelsWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::SensitivityLevel::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::SupportedSensitivityLevels::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} + +- (void)readAttributeDefaultSensitivityLevelWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = BooleanStateConfiguration::Attributes::DefaultSensitivityLevel::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeDefaultSensitivityLevelWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = BooleanStateConfiguration::Attributes::DefaultSensitivityLevel::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} + ++ (void)readAttributeDefaultSensitivityLevelWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = BooleanStateConfiguration::Attributes::DefaultSensitivityLevel::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -49175,7 +49271,7 @@ + (void)readAttributeSensitivityLevelWithClusterStateCache:(MTRClusterStateCache - (void)readAttributeAlarmsActiveWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsActive::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsActive::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49188,7 +49284,7 @@ - (void)subscribeAttributeAlarmsActiveWithParams:(MTRSubscribeParams * _Nonnull) subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsActive::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsActive::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49200,7 +49296,7 @@ - (void)subscribeAttributeAlarmsActiveWithParams:(MTRSubscribeParams * _Nonnull) + (void)readAttributeAlarmsActiveWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsActive::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsActive::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -49211,7 +49307,7 @@ + (void)readAttributeAlarmsActiveWithClusterStateCache:(MTRClusterStateCacheCont - (void)readAttributeAlarmsSuppressedWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsSuppressed::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsSuppressed::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49224,7 +49320,7 @@ - (void)subscribeAttributeAlarmsSuppressedWithParams:(MTRSubscribeParams * _Nonn subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsSuppressed::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsSuppressed::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49236,7 +49332,7 @@ - (void)subscribeAttributeAlarmsSuppressedWithParams:(MTRSubscribeParams * _Nonn + (void)readAttributeAlarmsSuppressedWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsSuppressed::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsSuppressed::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -49247,7 +49343,7 @@ + (void)readAttributeAlarmsSuppressedWithClusterStateCache:(MTRClusterStateCache - (void)readAttributeAlarmsEnabledWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsEnabled::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsEnabled::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49256,39 +49352,83 @@ - (void)readAttributeAlarmsEnabledWithCompletion:(void (^)(NSNumber * _Nullable completion:completion]; } -- (void)writeAttributeAlarmsEnabledWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion +- (void)subscribeAttributeAlarmsEnabledWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler { - [self writeAttributeAlarmsEnabledWithValue:(NSNumber * _Nonnull) value params:nil completion:completion]; + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsEnabled::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; } -- (void)writeAttributeAlarmsEnabledWithValue:(NSNumber * _Nonnull)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion + ++ (void)readAttributeAlarmsEnabledWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - // Make a copy of params before we go async. - params = [params copy]; - value = [value copy]; + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsEnabled::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; +} - auto * bridge = new MTRDefaultSuccessCallbackBridge(self.callbackQueue, ^(id _Nullable ignored, NSError * _Nullable error) { completion(error); }, ^(ExchangeManager & exchangeManager, const SessionHandle & session, DefaultSuccessCallbackType successCb, MTRErrorCallback failureCb, MTRCallbackBridgeBase * bridge) { - chip::Optional timedWriteTimeout; - if (params != nil) { - if (params.timedWriteTimeout != nil){ - timedWriteTimeout.SetValue(params.timedWriteTimeout.unsignedShortValue); - } - } +- (void)readAttributeAlarmsSupportedWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsSupported::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} - ListFreer listFreer; - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsEnabled::TypeInfo; - TypeInfo::Type cppValue; - cppValue = static_cast>(value.unsignedCharValue); +- (void)subscribeAttributeAlarmsSupportedWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +{ + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsSupported::TypeInfo; + [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:params + queue:self.callbackQueue + reportHandler:reportHandler + subscriptionEstablished:subscriptionEstablished]; +} - chip::Controller::ClusterBase cppCluster(exchangeManager, session, self.endpoint); - return cppCluster.WriteAttribute(cppValue, bridge, successCb, failureCb, timedWriteTimeout); }); - std::move(*bridge).DispatchAction(self.device); ++ (void)readAttributeAlarmsSupportedWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = BooleanStateConfiguration::Attributes::AlarmsSupported::TypeInfo; + [clusterStateCacheContainer + _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) + clusterID:TypeInfo::GetClusterId() + attributeID:TypeInfo::GetAttributeId() + queue:queue + completion:completion]; } -- (void)subscribeAttributeAlarmsEnabledWithParams:(MTRSubscribeParams * _Nonnull)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +- (void)readAttributeSensorFaultWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +{ + using TypeInfo = BooleanStateConfiguration::Attributes::SensorFault::TypeInfo; + [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) + clusterID:@(TypeInfo::GetClusterId()) + attributeID:@(TypeInfo::GetAttributeId()) + params:nil + queue:self.callbackQueue + completion:completion]; +} + +- (void)subscribeAttributeSensorFaultWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsEnabled::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::SensorFault::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49298,9 +49438,9 @@ - (void)subscribeAttributeAlarmsEnabledWithParams:(MTRSubscribeParams * _Nonnull subscriptionEstablished:subscriptionEstablished]; } -+ (void)readAttributeAlarmsEnabledWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion ++ (void)readAttributeSensorFaultWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AlarmsEnabled::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::SensorFault::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -49311,7 +49451,7 @@ + (void)readAttributeAlarmsEnabledWithClusterStateCache:(MTRClusterStateCacheCon - (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::GeneratedCommandList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::GeneratedCommandList::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49324,7 +49464,7 @@ - (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams * _ subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = BooleanSensorConfiguration::Attributes::GeneratedCommandList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::GeneratedCommandList::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49336,7 +49476,7 @@ - (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams * _ + (void)readAttributeGeneratedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::GeneratedCommandList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::GeneratedCommandList::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -49347,7 +49487,7 @@ + (void)readAttributeGeneratedCommandListWithClusterStateCache:(MTRClusterStateC - (void)readAttributeAcceptedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AcceptedCommandList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AcceptedCommandList::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49360,7 +49500,7 @@ - (void)subscribeAttributeAcceptedCommandListWithParams:(MTRSubscribeParams * _N subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = BooleanSensorConfiguration::Attributes::AcceptedCommandList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AcceptedCommandList::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49372,7 +49512,7 @@ - (void)subscribeAttributeAcceptedCommandListWithParams:(MTRSubscribeParams * _N + (void)readAttributeAcceptedCommandListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AcceptedCommandList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AcceptedCommandList::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -49383,7 +49523,7 @@ + (void)readAttributeAcceptedCommandListWithClusterStateCache:(MTRClusterStateCa - (void)readAttributeEventListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::EventList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::EventList::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49396,7 +49536,7 @@ - (void)subscribeAttributeEventListWithParams:(MTRSubscribeParams * _Nonnull)par subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = BooleanSensorConfiguration::Attributes::EventList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::EventList::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49408,7 +49548,7 @@ - (void)subscribeAttributeEventListWithParams:(MTRSubscribeParams * _Nonnull)par + (void)readAttributeEventListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::EventList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::EventList::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -49419,7 +49559,7 @@ + (void)readAttributeEventListWithClusterStateCache:(MTRClusterStateCacheContain - (void)readAttributeAttributeListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AttributeList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AttributeList::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49432,7 +49572,7 @@ - (void)subscribeAttributeAttributeListWithParams:(MTRSubscribeParams * _Nonnull subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = BooleanSensorConfiguration::Attributes::AttributeList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AttributeList::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49444,7 +49584,7 @@ - (void)subscribeAttributeAttributeListWithParams:(MTRSubscribeParams * _Nonnull + (void)readAttributeAttributeListWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::AttributeList::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::AttributeList::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -49455,7 +49595,7 @@ + (void)readAttributeAttributeListWithClusterStateCache:(MTRClusterStateCacheCon - (void)readAttributeFeatureMapWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::FeatureMap::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::FeatureMap::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49468,7 +49608,7 @@ - (void)subscribeAttributeFeatureMapWithParams:(MTRSubscribeParams * _Nonnull)pa subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = BooleanSensorConfiguration::Attributes::FeatureMap::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::FeatureMap::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49480,7 +49620,7 @@ - (void)subscribeAttributeFeatureMapWithParams:(MTRSubscribeParams * _Nonnull)pa + (void)readAttributeFeatureMapWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::FeatureMap::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::FeatureMap::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -49491,7 +49631,7 @@ + (void)readAttributeFeatureMapWithClusterStateCache:(MTRClusterStateCacheContai - (void)readAttributeClusterRevisionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::ClusterRevision::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::ClusterRevision::TypeInfo; [self.device _readKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49504,7 +49644,7 @@ - (void)subscribeAttributeClusterRevisionWithParams:(MTRSubscribeParams * _Nonnu subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = BooleanSensorConfiguration::Attributes::ClusterRevision::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::ClusterRevision::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:@(self.endpoint) clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -49516,7 +49656,7 @@ - (void)subscribeAttributeClusterRevisionWithParams:(MTRSubscribeParams * _Nonnu + (void)readAttributeClusterRevisionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = BooleanSensorConfiguration::Attributes::ClusterRevision::TypeInfo; + using TypeInfo = BooleanStateConfiguration::Attributes::ClusterRevision::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index 82c2cbc34bc9f5..0ed485f03948a7 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -148,7 +148,7 @@ typedef NS_ENUM(uint32_t, MTRClusterIDType) { MTRClusterIDTypeRVCOperationalStateID MTR_NEWLY_AVAILABLE = 0x00000061, MTRClusterIDTypeHEPAFilterMonitoringID MTR_PROVISIONALLY_AVAILABLE = 0x00000071, MTRClusterIDTypeActivatedCarbonFilterMonitoringID MTR_PROVISIONALLY_AVAILABLE = 0x00000072, - MTRClusterIDTypeBooleanSensorConfigurationID MTR_PROVISIONALLY_AVAILABLE = 0x00000080, + MTRClusterIDTypeBooleanStateConfigurationID MTR_PROVISIONALLY_AVAILABLE = 0x00000080, MTRClusterIDTypeValveConfigurationAndControlID MTR_PROVISIONALLY_AVAILABLE = 0x00000081, MTRClusterIDTypeElectricalEnergyMeasurementID MTR_PROVISIONALLY_AVAILABLE = 0x00000091, MTRClusterIDTypeDemandResponseLoadControlID MTR_PROVISIONALLY_AVAILABLE = 0x00000096, @@ -2576,17 +2576,21 @@ typedef NS_ENUM(uint32_t, MTRAttributeIDType) { MTRAttributeIDTypeClusterActivatedCarbonFilterMonitoringAttributeFeatureMapID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeFeatureMapID, MTRAttributeIDTypeClusterActivatedCarbonFilterMonitoringAttributeClusterRevisionID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, - // Cluster BooleanSensorConfiguration attributes - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeSensitivityLevelID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAlarmsActiveID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAlarmsSuppressedID MTR_PROVISIONALLY_AVAILABLE = 0x00000002, - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAlarmsEnabledID MTR_PROVISIONALLY_AVAILABLE = 0x00000003, - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeGeneratedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAcceptedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID, - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeEventListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeEventListID, - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAttributeListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAttributeListID, - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeFeatureMapID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeFeatureMapID, - MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeClusterRevisionID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, + // Cluster BooleanStateConfiguration attributes + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeCurrentSensitivityLevelID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeSupportedSensitivityLevelsID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeDefaultSensitivityLevelID MTR_PROVISIONALLY_AVAILABLE = 0x00000002, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAlarmsActiveID MTR_PROVISIONALLY_AVAILABLE = 0x00000003, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAlarmsSuppressedID MTR_PROVISIONALLY_AVAILABLE = 0x00000004, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAlarmsEnabledID MTR_PROVISIONALLY_AVAILABLE = 0x00000005, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAlarmsSupportedID MTR_PROVISIONALLY_AVAILABLE = 0x00000006, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeSensorFaultID MTR_PROVISIONALLY_AVAILABLE = 0x00000007, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeGeneratedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAcceptedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeEventListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeEventListID, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAttributeListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeAttributeListID, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeFeatureMapID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeFeatureMapID, + MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeClusterRevisionID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, // Cluster ValveConfigurationAndControl attributes MTRAttributeIDTypeClusterValveConfigurationAndControlAttributeOpenDurationID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, @@ -6246,8 +6250,9 @@ typedef NS_ENUM(uint32_t, MTRCommandIDType) { // Cluster ActivatedCarbonFilterMonitoring commands MTRCommandIDTypeClusterActivatedCarbonFilterMonitoringCommandResetConditionID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, - // Cluster BooleanSensorConfiguration commands - MTRCommandIDTypeClusterBooleanSensorConfigurationCommandSuppressRequestID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + // Cluster BooleanStateConfiguration commands + MTRCommandIDTypeClusterBooleanStateConfigurationCommandSuppressAlarmID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTRCommandIDTypeClusterBooleanStateConfigurationCommandEnableDisableAlarmID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, // Cluster ValveConfigurationAndControl commands MTRCommandIDTypeClusterValveConfigurationAndControlCommandOpenID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, @@ -7144,9 +7149,9 @@ typedef NS_ENUM(uint32_t, MTREventIDType) { MTREventIDTypeClusterRVCOperationalStateEventOperationalErrorID MTR_NEWLY_AVAILABLE = 0x00000000, MTREventIDTypeClusterRVCOperationalStateEventOperationCompletionID MTR_NEWLY_AVAILABLE = 0x00000001, - // Cluster BooleanSensorConfiguration events - MTREventIDTypeClusterBooleanSensorConfigurationEventAlarmsStateChangedID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, - MTREventIDTypeClusterBooleanSensorConfigurationEventSensorFaultID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, + // Cluster BooleanStateConfiguration events + MTREventIDTypeClusterBooleanStateConfigurationEventAlarmsStateChangedID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTREventIDTypeClusterBooleanStateConfigurationEventSensorFaultID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, // Cluster ValveConfigurationAndControl events MTREventIDTypeClusterValveConfigurationAndControlEventValveStateChangedID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index 1b16379ce6eb58..287407184597ce 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -3311,25 +3311,32 @@ MTR_PROVISIONALLY_AVAILABLE @end /** - * Cluster Boolean Sensor Configuration + * Cluster Boolean State Configuration * This cluster is used to configure a boolean sensor. */ MTR_PROVISIONALLY_AVAILABLE -@interface MTRClusterBooleanSensorConfiguration : MTRGenericCluster +@interface MTRClusterBooleanStateConfiguration : MTRGenericCluster -- (void)suppressRequestWithParams:(MTRBooleanSensorConfigurationClusterSuppressRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)suppressAlarmWithParams:(MTRBooleanStateConfigurationClusterSuppressAlarmParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)enableDisableAlarmWithParams:(MTRBooleanStateConfigurationClusterEnableDisableAlarmParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (NSDictionary * _Nullable)readAttributeSensitivityLevelWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeSensitivityLevelWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeSensitivityLevelWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; +- (NSDictionary * _Nullable)readAttributeCurrentSensitivityLevelWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; +- (void)writeAttributeCurrentSensitivityLevelWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs MTR_PROVISIONALLY_AVAILABLE; +- (void)writeAttributeCurrentSensitivityLevelWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeSupportedSensitivityLevelsWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeDefaultSensitivityLevelWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeAlarmsActiveWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeAlarmsSuppressedWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeAlarmsEnabledWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeAlarmsEnabledWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeAlarmsEnabledWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeAlarmsSupportedWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; + +- (NSDictionary * _Nullable)readAttributeSensorFaultWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; @@ -3348,7 +3355,7 @@ MTR_PROVISIONALLY_AVAILABLE @end -@interface MTRClusterBooleanSensorConfiguration (Availability) +@interface MTRClusterBooleanStateConfiguration (Availability) /** * For all instance methods that take a completion (i.e. command invocations), diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index fbf736a5882e3e..1108e9c4678a67 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -8948,12 +8948,12 @@ - (void)writeAttributeLastChangedTimeWithValue:(NSDictionary *)d @end -@implementation MTRClusterBooleanSensorConfiguration +@implementation MTRClusterBooleanStateConfiguration -- (void)suppressRequestWithParams:(MTRBooleanSensorConfigurationClusterSuppressRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion +- (void)suppressAlarmWithParams:(MTRBooleanStateConfigurationClusterSuppressAlarmParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion { if (params == nil) { - params = [[MTRBooleanSensorConfigurationClusterSuppressRequestParams + params = [[MTRBooleanStateConfigurationClusterSuppressAlarmParams alloc] init]; } @@ -8963,7 +8963,7 @@ - (void)suppressRequestWithParams:(MTRBooleanSensorConfigurationClusterSuppressR auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - using RequestType = BooleanSensorConfiguration::Commands::SuppressRequest::Type; + using RequestType = BooleanStateConfiguration::Commands::SuppressAlarm::Type; [self.device _invokeKnownCommandWithEndpointID:@(self.endpoint) clusterID:@(RequestType::GetClusterId()) commandID:@(RequestType::GetCommandId()) @@ -8977,76 +8977,112 @@ - (void)suppressRequestWithParams:(MTRBooleanSensorConfigurationClusterSuppressR completion:responseHandler]; } -- (NSDictionary * _Nullable)readAttributeSensitivityLevelWithParams:(MTRReadParams * _Nullable)params +- (void)enableDisableAlarmWithParams:(MTRBooleanStateConfigurationClusterEnableDisableAlarmParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeSensitivityLevelID) params:params]; + if (params == nil) { + params = [[MTRBooleanStateConfigurationClusterEnableDisableAlarmParams + alloc] init]; + } + + auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { + completion(error); + }; + + auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; + + using RequestType = BooleanStateConfiguration::Commands::EnableDisableAlarm::Type; + [self.device _invokeKnownCommandWithEndpointID:@(self.endpoint) + clusterID:@(RequestType::GetClusterId()) + commandID:@(RequestType::GetCommandId()) + commandPayload:params + expectedValues:expectedValues + expectedValueInterval:expectedValueIntervalMs + timedInvokeTimeout:timedInvokeTimeoutMs + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.callbackQueue + completion:responseHandler]; } -- (void)writeAttributeSensitivityLevelWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs +- (NSDictionary * _Nullable)readAttributeCurrentSensitivityLevelWithParams:(MTRReadParams * _Nullable)params { - [self writeAttributeSensitivityLevelWithValue:dataValueDictionary expectedValueInterval:expectedValueIntervalMs params:nil]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeCurrentSensitivityLevelID) params:params]; } -- (void)writeAttributeSensitivityLevelWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params + +- (void)writeAttributeCurrentSensitivityLevelWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs +{ + [self writeAttributeCurrentSensitivityLevelWithValue:dataValueDictionary expectedValueInterval:expectedValueIntervalMs params:nil]; +} +- (void)writeAttributeCurrentSensitivityLevelWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params { NSNumber * timedWriteTimeout = params.timedWriteTimeout; - [self.device writeAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeSensitivityLevelID) value:dataValueDictionary expectedValueInterval:expectedValueIntervalMs timedWriteTimeout:timedWriteTimeout]; + [self.device writeAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeCurrentSensitivityLevelID) value:dataValueDictionary expectedValueInterval:expectedValueIntervalMs timedWriteTimeout:timedWriteTimeout]; +} + +- (NSDictionary * _Nullable)readAttributeSupportedSensitivityLevelsWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeSupportedSensitivityLevelsID) params:params]; +} + +- (NSDictionary * _Nullable)readAttributeDefaultSensitivityLevelWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeDefaultSensitivityLevelID) params:params]; } - (NSDictionary * _Nullable)readAttributeAlarmsActiveWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAlarmsActiveID) params:params]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAlarmsActiveID) params:params]; } - (NSDictionary * _Nullable)readAttributeAlarmsSuppressedWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAlarmsSuppressedID) params:params]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAlarmsSuppressedID) params:params]; } - (NSDictionary * _Nullable)readAttributeAlarmsEnabledWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAlarmsEnabledID) params:params]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAlarmsEnabledID) params:params]; } -- (void)writeAttributeAlarmsEnabledWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs +- (NSDictionary * _Nullable)readAttributeAlarmsSupportedWithParams:(MTRReadParams * _Nullable)params { - [self writeAttributeAlarmsEnabledWithValue:dataValueDictionary expectedValueInterval:expectedValueIntervalMs params:nil]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAlarmsSupportedID) params:params]; } -- (void)writeAttributeAlarmsEnabledWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params -{ - NSNumber * timedWriteTimeout = params.timedWriteTimeout; - [self.device writeAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAlarmsEnabledID) value:dataValueDictionary expectedValueInterval:expectedValueIntervalMs timedWriteTimeout:timedWriteTimeout]; +- (NSDictionary * _Nullable)readAttributeSensorFaultWithParams:(MTRReadParams * _Nullable)params +{ + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeSensorFaultID) params:params]; } - (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeGeneratedCommandListID) params:params]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeGeneratedCommandListID) params:params]; } - (NSDictionary * _Nullable)readAttributeAcceptedCommandListWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAcceptedCommandListID) params:params]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAcceptedCommandListID) params:params]; } - (NSDictionary * _Nullable)readAttributeEventListWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeEventListID) params:params]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeEventListID) params:params]; } - (NSDictionary * _Nullable)readAttributeAttributeListWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeAttributeListID) params:params]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeAttributeListID) params:params]; } - (NSDictionary * _Nullable)readAttributeFeatureMapWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeFeatureMapID) params:params]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeFeatureMapID) params:params]; } - (NSDictionary * _Nullable)readAttributeClusterRevisionWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanSensorConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanSensorConfigurationAttributeClusterRevisionID) params:params]; + return [self.device readAttributeWithEndpointID:@(self.endpoint) clusterID:@(MTRClusterIDTypeBooleanStateConfigurationID) attributeID:@(MTRAttributeIDTypeClusterBooleanStateConfigurationAttributeClusterRevisionID) params:params]; } @end diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index cfb637526a9025..e01bdabcb6a987 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -5596,7 +5596,7 @@ MTR_PROVISIONALLY_AVAILABLE @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRBooleanSensorConfigurationClusterSuppressRequestParams : NSObject +@interface MTRBooleanStateConfigurationClusterSuppressAlarmParams : NSObject @property (nonatomic, copy) NSNumber * _Nonnull alarmsToSuppress MTR_PROVISIONALLY_AVAILABLE; /** @@ -5625,6 +5625,36 @@ MTR_PROVISIONALLY_AVAILABLE @property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; @end +MTR_PROVISIONALLY_AVAILABLE +@interface MTRBooleanStateConfigurationClusterEnableDisableAlarmParams : NSObject + +@property (nonatomic, copy) NSNumber * _Nonnull alarmsToEnableDisable MTR_PROVISIONALLY_AVAILABLE; +/** + * Controls whether the command is a timed command (using Timed Invoke). + * + * If nil (the default value), a regular invoke is done for commands that do + * not require a timed invoke and a timed invoke with some default timed request + * timeout is done for commands that require a timed invoke. + * + * If not nil, a timed invoke is done, with the provided value used as the timed + * request timeout. The value should be chosen small enough to provide the + * desired security properties but large enough that it will allow a round-trip + * from the sever to the client (for the status response and actual invoke + * request) within the timeout window. + * + */ +@property (nonatomic, copy, nullable) NSNumber * timedInvokeTimeoutMs; + +/** + * Controls how much time, in seconds, we will allow for the server to process the command. + * + * The command will then time out if that much time, plus an allowance for retransmits due to network failures, passes. + * + * If nil, the framework will try to select an appropriate timeout value itself. + */ +@property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; +@end + MTR_PROVISIONALLY_AVAILABLE @interface MTRValveConfigurationAndControlClusterOpenParams : NSObject diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index 5d47571ec5ad3e..7e7eccfb8043ca 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -15382,7 +15382,7 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader } @end -@implementation MTRBooleanSensorConfigurationClusterSuppressRequestParams +@implementation MTRBooleanStateConfigurationClusterSuppressAlarmParams - (instancetype)init { if (self = [super init]) { @@ -15396,7 +15396,7 @@ - (instancetype)init - (id)copyWithZone:(NSZone * _Nullable)zone; { - auto other = [[MTRBooleanSensorConfigurationClusterSuppressRequestParams alloc] init]; + auto other = [[MTRBooleanStateConfigurationClusterSuppressAlarmParams alloc] init]; other.alarmsToSuppress = self.alarmsToSuppress; other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; @@ -15413,11 +15413,11 @@ - (NSString *)description @end -@implementation MTRBooleanSensorConfigurationClusterSuppressRequestParams (InternalMethods) +@implementation MTRBooleanStateConfigurationClusterSuppressAlarmParams (InternalMethods) - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader { - chip::app::Clusters::BooleanSensorConfiguration::Commands::SuppressRequest::Type encodableStruct; + chip::app::Clusters::BooleanStateConfiguration::Commands::SuppressAlarm::Type encodableStruct; ListFreer listFreer; { encodableStruct.alarmsToSuppress = static_cast>(self.alarmsToSuppress.unsignedCharValue); @@ -15461,6 +15461,85 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader } @end +@implementation MTRBooleanStateConfigurationClusterEnableDisableAlarmParams +- (instancetype)init +{ + if (self = [super init]) { + + _alarmsToEnableDisable = @(0); + _timedInvokeTimeoutMs = nil; + _serverSideProcessingTimeout = nil; + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone; +{ + auto other = [[MTRBooleanStateConfigurationClusterEnableDisableAlarmParams alloc] init]; + + other.alarmsToEnableDisable = self.alarmsToEnableDisable; + other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; + other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: alarmsToEnableDisable:%@; >", NSStringFromClass([self class]), _alarmsToEnableDisable]; + return descriptionString; +} + +@end + +@implementation MTRBooleanStateConfigurationClusterEnableDisableAlarmParams (InternalMethods) + +- (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader +{ + chip::app::Clusters::BooleanStateConfiguration::Commands::EnableDisableAlarm::Type encodableStruct; + ListFreer listFreer; + { + encodableStruct.alarmsToEnableDisable = static_cast>(self.alarmsToEnableDisable.unsignedCharValue); + } + + auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); + if (buffer.IsNull()) { + return CHIP_ERROR_NO_MEMORY; + } + + chip::System::PacketBufferTLVWriter writer; + // Commands never need chained buffers, since they cannot be chunked. + writer.Init(std::move(buffer), /* useChainedBuffers = */ false); + + ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::AnonymousTag(), encodableStruct)); + + ReturnErrorOnFailure(writer.Finalize(&buffer)); + + reader.Init(std::move(buffer)); + return reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()); +} + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error +{ + chip::System::PacketBufferTLVReader reader; + CHIP_ERROR err = [self _encodeToTLVReader:reader]; + if (err != CHIP_NO_ERROR) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:err]; + } + return nil; + } + + auto decodedObj = MTRDecodeDataValueDictionaryFromCHIPTLV(&reader); + if (decodedObj == nil) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]; + } + } + return decodedObj; +} +@end + @implementation MTRValveConfigurationAndControlClusterOpenParams - (instancetype)init { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h index 54b6b8159bc576..f5738ad6af5b1b 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h @@ -994,7 +994,13 @@ NS_ASSUME_NONNULL_BEGIN @end -@interface MTRBooleanSensorConfigurationClusterSuppressRequestParams (InternalMethods) +@interface MTRBooleanStateConfigurationClusterSuppressAlarmParams (InternalMethods) + +- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; + +@end + +@interface MTRBooleanStateConfigurationClusterEnableDisableAlarmParams (InternalMethods) - (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm index a3dbd7d0369423..8d20da304754e6 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandTimedCheck.mm @@ -572,9 +572,9 @@ static BOOL CommandNeedsTimedInvokeInActivatedCarbonFilterMonitoringCluster(Attr } } } -static BOOL CommandNeedsTimedInvokeInBooleanSensorConfigurationCluster(AttributeId aAttributeId) +static BOOL CommandNeedsTimedInvokeInBooleanStateConfigurationCluster(AttributeId aAttributeId) { - using namespace Clusters::BooleanSensorConfiguration; + using namespace Clusters::BooleanStateConfiguration; switch (aAttributeId) { default: { return NO; @@ -1248,8 +1248,8 @@ BOOL MTRCommandNeedsTimedInvoke(NSNumber * _Nonnull aClusterID, NSNumber * _Nonn case Clusters::ActivatedCarbonFilterMonitoring::Id: { return CommandNeedsTimedInvokeInActivatedCarbonFilterMonitoringCluster(commandID); } - case Clusters::BooleanSensorConfiguration::Id: { - return CommandNeedsTimedInvokeInBooleanSensorConfigurationCluster(commandID); + case Clusters::BooleanStateConfiguration::Id: { + return CommandNeedsTimedInvokeInBooleanStateConfigurationCluster(commandID); } case Clusters::ValveConfigurationAndControl::Id: { return CommandNeedsTimedInvokeInValveConfigurationAndControlCluster(commandID); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm index 6d287e47b2fd58..20b8ec3138d5da 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm @@ -54,9 +54,10 @@ { 0x0000002B, DeviceTypeClass::Simple, "Matter Fan" }, { 0x0000002C, DeviceTypeClass::Simple, "Matter Air Quality Sensor" }, { 0x0000002D, DeviceTypeClass::Simple, "Matter Air Purifier" }, - { 0x00000041, DeviceTypeClass::Simple, "Matter Boolean Sensor" }, + { 0x00000041, DeviceTypeClass::Simple, "Matter Water Freeze Detector" }, { 0x00000042, DeviceTypeClass::Simple, "Matter Valve" }, { 0x00000043, DeviceTypeClass::Simple, "Matter Water Leak Detector" }, + { 0x00000044, DeviceTypeClass::Simple, "Matter Rain Sensor" }, { 0x00000070, DeviceTypeClass::Simple, "Matter Refrigerator" }, { 0x00000071, DeviceTypeClass::Simple, "Matter Temperature Controlled Cabinet" }, { 0x00000072, DeviceTypeClass::Simple, "Matter Room Air Conditioner" }, diff --git a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm index fdffaae3ca3761..b8d26c67791e00 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTREventTLVValueDecoder.mm @@ -2366,9 +2366,9 @@ static id _Nullable DecodeEventPayloadForActivatedCarbonFilterMonitoringCluster( *aError = CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB; return nil; } -static id _Nullable DecodeEventPayloadForBooleanSensorConfigurationCluster(EventId aEventId, TLV::TLVReader & aReader, CHIP_ERROR * aError) +static id _Nullable DecodeEventPayloadForBooleanStateConfigurationCluster(EventId aEventId, TLV::TLVReader & aReader, CHIP_ERROR * aError) { - using namespace Clusters::BooleanSensorConfiguration; + using namespace Clusters::BooleanStateConfiguration; switch (aEventId) { case Events::AlarmsStateChanged::Id: { Events::AlarmsStateChanged::DecodableType cppValue; @@ -2377,7 +2377,7 @@ static id _Nullable DecodeEventPayloadForBooleanSensorConfigurationCluster(Event return nil; } - __auto_type * value = [MTRBooleanSensorConfigurationClusterAlarmsStateChangedEvent new]; + __auto_type * value = [MTRBooleanStateConfigurationClusterAlarmsStateChangedEvent new]; do { NSNumber * _Nonnull memberValue; @@ -2403,7 +2403,13 @@ static id _Nullable DecodeEventPayloadForBooleanSensorConfigurationCluster(Event return nil; } - __auto_type * value = [MTRBooleanSensorConfigurationClusterSensorFaultEvent new]; + __auto_type * value = [MTRBooleanStateConfigurationClusterSensorFaultEvent new]; + + do { + NSNumber * _Nonnull memberValue; + memberValue = [NSNumber numberWithUnsignedShort:cppValue.sensorFault.Raw()]; + value.sensorFault = memberValue; + } while (0); return value; } @@ -4449,8 +4455,8 @@ id _Nullable MTRDecodeEventPayload(const ConcreteEventPath & aPath, TLV::TLVRead case Clusters::ActivatedCarbonFilterMonitoring::Id: { return DecodeEventPayloadForActivatedCarbonFilterMonitoringCluster(aPath.mEventId, aReader, aError); } - case Clusters::BooleanSensorConfiguration::Id: { - return DecodeEventPayloadForBooleanSensorConfigurationCluster(aPath.mEventId, aReader, aError); + case Clusters::BooleanStateConfiguration::Id: { + return DecodeEventPayloadForBooleanStateConfigurationCluster(aPath.mEventId, aReader, aError); } case Clusters::ValveConfigurationAndControl::Id: { return DecodeEventPayloadForValveConfigurationAndControlCluster(aPath.mEventId, aReader, aError); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h index 8a1ba6e5fd330b..f879cf7be69982 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h @@ -1053,13 +1053,14 @@ MTR_PROVISIONALLY_AVAILABLE @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRBooleanSensorConfigurationClusterAlarmsStateChangedEvent : NSObject +@interface MTRBooleanStateConfigurationClusterAlarmsStateChangedEvent : NSObject @property (nonatomic, copy) NSNumber * _Nonnull alarmsActive MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSNumber * _Nullable alarmsSuppressed MTR_PROVISIONALLY_AVAILABLE; @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRBooleanSensorConfigurationClusterSensorFaultEvent : NSObject +@interface MTRBooleanStateConfigurationClusterSensorFaultEvent : NSObject +@property (nonatomic, copy) NSNumber * _Nonnull sensorFault MTR_PROVISIONALLY_AVAILABLE; @end MTR_PROVISIONALLY_AVAILABLE diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm index 4c08c7228fd870..12aa87d41c1c4e 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm @@ -4203,7 +4203,7 @@ - (NSString *)description @end -@implementation MTRBooleanSensorConfigurationClusterAlarmsStateChangedEvent +@implementation MTRBooleanStateConfigurationClusterAlarmsStateChangedEvent - (instancetype)init { if (self = [super init]) { @@ -4217,7 +4217,7 @@ - (instancetype)init - (id)copyWithZone:(NSZone * _Nullable)zone { - auto other = [[MTRBooleanSensorConfigurationClusterAlarmsStateChangedEvent alloc] init]; + auto other = [[MTRBooleanStateConfigurationClusterAlarmsStateChangedEvent alloc] init]; other.alarmsActive = self.alarmsActive; other.alarmsSuppressed = self.alarmsSuppressed; @@ -4233,24 +4233,28 @@ - (NSString *)description @end -@implementation MTRBooleanSensorConfigurationClusterSensorFaultEvent +@implementation MTRBooleanStateConfigurationClusterSensorFaultEvent - (instancetype)init { if (self = [super init]) { + + _sensorFault = @(0); } return self; } - (id)copyWithZone:(NSZone * _Nullable)zone { - auto other = [[MTRBooleanSensorConfigurationClusterSensorFaultEvent alloc] init]; + auto other = [[MTRBooleanStateConfigurationClusterSensorFaultEvent alloc] init]; + + other.sensorFault = self.sensorFault; return other; } - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: >", NSStringFromClass([self class])]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: sensorFault:%@; >", NSStringFromClass([self class]), _sensorFault]; return descriptionString; } diff --git a/src/python_testing/TC_BSENCFG_2_1.py b/src/python_testing/TC_BSENCFG_2_1.py index f9a8c003d5be26..0312b131a77590 100644 --- a/src/python_testing/TC_BSENCFG_2_1.py +++ b/src/python_testing/TC_BSENCFG_2_1.py @@ -24,7 +24,7 @@ class TC_BSENCFG_2_1(MatterBaseTest): async def read_ts_attribute_expect_success(self, endpoint, attribute): - cluster = Clusters.Objects.BooleanSensorConfiguration + cluster = Clusters.Objects.BooleanStateConfiguration return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) @async_test_body @@ -33,7 +33,7 @@ async def test_TC_BSENCFG_2_1(self): endpoint = self.user_params.get("endpoint", 1) self.print_step(1, "Commissioning, already done") - attributes = Clusters.BooleanSensorConfiguration.Attributes + attributes = Clusters.BooleanStateConfiguration.Attributes self.print_step(2, "Read attribute list to determine supported attributes") attribute_list = await self.read_ts_attribute_expect_success(endpoint=endpoint, attribute=attributes.AttributeList) @@ -41,7 +41,7 @@ async def test_TC_BSENCFG_2_1(self): self.print_step(3, "Read SensitivityLevel attribute, if supported") if attributes.SensitivityLevel.attribute_id in attribute_list: sensitivity_level_dut = await self.read_ts_attribute_expect_success(endpoint=endpoint, attribute=attributes.SensitivityLevel) - asserts.assert_less(sensitivity_level_dut, Clusters.Objects.BooleanSensorConfiguration.Enums.SensitivityEnum.kUnknownEnumValue, + asserts.assert_less(sensitivity_level_dut, Clusters.Objects.BooleanStateConfiguration.Enums.SensitivityEnum.kUnknownEnumValue, "SensitivityLevel is not in valid range") else: logging.info("Test step skipped") diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp index 77c7512374fa94..d2f762fd845a6c 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp @@ -9282,17 +9282,79 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value) } // namespace Attributes } // namespace ActivatedCarbonFilterMonitoring -namespace BooleanSensorConfiguration { +namespace BooleanStateConfiguration { namespace Attributes { -namespace SensitivityLevel { +namespace CurrentSensitivityLevel { -EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::BooleanSensorConfiguration::SensitivityEnum * value) +EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + *value = Traits::StorageToWorking(temp); + return status; +} +EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, writable, ZCL_INT8U_ATTRIBUTE_TYPE); +} + +} // namespace CurrentSensitivityLevel + +namespace SupportedSensitivityLevels { + +EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value) +{ + using Traits = NumericAttributeTraits; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + *value = Traits::StorageToWorking(temp); + return status; +} +EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value) +{ + using Traits = NumericAttributeTraits; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, writable, ZCL_INT8U_ATTRIBUTE_TYPE); +} + +} // namespace SupportedSensitivityLevels + +namespace DefaultSensitivityLevel { + +EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanSensorConfiguration::Id, Id, readable, sizeof(temp)); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) { @@ -9301,9 +9363,9 @@ EmberAfStatus Get(chip::EndpointId endpoint, chip::app::Clusters::BooleanSensorC *value = Traits::StorageToWorking(temp); return status; } -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::BooleanSensorConfiguration::SensitivityEnum value) +EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; @@ -9311,20 +9373,19 @@ EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::BooleanSensorC Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::BooleanSensorConfiguration::Id, Id, writable, ZCL_ENUM8_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, writable, ZCL_INT8U_ATTRIBUTE_TYPE); } -} // namespace SensitivityLevel +} // namespace DefaultSensitivityLevel namespace AlarmsActive { -EmberAfStatus Get(chip::EndpointId endpoint, - chip::BitMask * value) +EmberAfStatus Get(chip::EndpointId endpoint, chip::BitMask * value) { - using Traits = NumericAttributeTraits>; + using Traits = NumericAttributeTraits>; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanSensorConfiguration::Id, Id, readable, sizeof(temp)); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) { @@ -9333,9 +9394,9 @@ EmberAfStatus Get(chip::EndpointId endpoint, *value = Traits::StorageToWorking(temp); return status; } -EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value) +EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value) { - using Traits = NumericAttributeTraits>; + using Traits = NumericAttributeTraits>; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; @@ -9343,20 +9404,19 @@ EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask * value) +EmberAfStatus Get(chip::EndpointId endpoint, chip::BitMask * value) { - using Traits = NumericAttributeTraits>; + using Traits = NumericAttributeTraits>; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanSensorConfiguration::Id, Id, readable, sizeof(temp)); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) { @@ -9365,9 +9425,9 @@ EmberAfStatus Get(chip::EndpointId endpoint, *value = Traits::StorageToWorking(temp); return status; } -EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value) +EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value) { - using Traits = NumericAttributeTraits>; + using Traits = NumericAttributeTraits>; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; @@ -9375,20 +9435,19 @@ EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask * value) +EmberAfStatus Get(chip::EndpointId endpoint, chip::BitMask * value) { - using Traits = NumericAttributeTraits>; + using Traits = NumericAttributeTraits>; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanSensorConfiguration::Id, Id, readable, sizeof(temp)); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) { @@ -9397,9 +9456,9 @@ EmberAfStatus Get(chip::EndpointId endpoint, *value = Traits::StorageToWorking(temp); return status; } -EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value) +EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value) { - using Traits = NumericAttributeTraits>; + using Traits = NumericAttributeTraits>; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; @@ -9407,11 +9466,74 @@ EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask * value) +{ + using Traits = NumericAttributeTraits>; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + *value = Traits::StorageToWorking(temp); + return status; +} +EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value) +{ + using Traits = NumericAttributeTraits>; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, writable, ZCL_BITMAP8_ATTRIBUTE_TYPE); +} + +} // namespace AlarmsSupported + +namespace SensorFault { + +EmberAfStatus Get(chip::EndpointId endpoint, + chip::BitMask * value) +{ + using Traits = NumericAttributeTraits>; + Traits::StorageType temp; + uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); + VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); + if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + *value = Traits::StorageToWorking(temp); + return status; +} +EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value) +{ + using Traits = NumericAttributeTraits>; + if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) + { + return EMBER_ZCL_STATUS_CONSTRAINT_ERROR; + } + Traits::StorageType storageValue; + Traits::WorkingToStorage(value, storageValue); + uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); + return emberAfWriteAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, writable, ZCL_BITMAP16_ATTRIBUTE_TYPE); +} + +} // namespace SensorFault + namespace FeatureMap { EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value) @@ -9419,7 +9541,7 @@ EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value) using Traits = NumericAttributeTraits; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanSensorConfiguration::Id, Id, readable, sizeof(temp)); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) { @@ -9438,7 +9560,7 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value) Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::BooleanSensorConfiguration::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, writable, ZCL_BITMAP32_ATTRIBUTE_TYPE); } } // namespace FeatureMap @@ -9450,7 +9572,7 @@ EmberAfStatus Get(chip::EndpointId endpoint, uint16_t * value) using Traits = NumericAttributeTraits; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanSensorConfiguration::Id, Id, readable, sizeof(temp)); + EmberAfStatus status = emberAfReadAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, readable, sizeof(temp)); VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == status, status); if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) { @@ -9469,13 +9591,13 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value) Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::BooleanSensorConfiguration::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::BooleanStateConfiguration::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); } } // namespace ClusterRevision } // namespace Attributes -} // namespace BooleanSensorConfiguration +} // namespace BooleanStateConfiguration namespace ValveConfigurationAndControl { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index 2fdeaa1fdc71e7..af68f1c28926d1 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -1819,33 +1819,55 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value); } // namespace Attributes } // namespace ActivatedCarbonFilterMonitoring -namespace BooleanSensorConfiguration { +namespace BooleanStateConfiguration { namespace Attributes { -namespace SensitivityLevel { -EmberAfStatus Get(chip::EndpointId endpoint, - chip::app::Clusters::BooleanSensorConfiguration::SensitivityEnum * value); // SensitivityEnum -EmberAfStatus Set(chip::EndpointId endpoint, chip::app::Clusters::BooleanSensorConfiguration::SensitivityEnum value); -} // namespace SensitivityLevel +namespace CurrentSensitivityLevel { +EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value); // int8u +EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value); +} // namespace CurrentSensitivityLevel + +namespace SupportedSensitivityLevels { +EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value); // int8u +EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value); +} // namespace SupportedSensitivityLevels + +namespace DefaultSensitivityLevel { +EmberAfStatus Get(chip::EndpointId endpoint, uint8_t * value); // int8u +EmberAfStatus Set(chip::EndpointId endpoint, uint8_t value); +} // namespace DefaultSensitivityLevel namespace AlarmsActive { EmberAfStatus Get(chip::EndpointId endpoint, - chip::BitMask * value); // AlarmModeBitmap -EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value); + chip::BitMask * value); // AlarmModeBitmap +EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value); } // namespace AlarmsActive namespace AlarmsSuppressed { EmberAfStatus Get(chip::EndpointId endpoint, - chip::BitMask * value); // AlarmModeBitmap -EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value); + chip::BitMask * value); // AlarmModeBitmap +EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value); } // namespace AlarmsSuppressed namespace AlarmsEnabled { EmberAfStatus Get(chip::EndpointId endpoint, - chip::BitMask * value); // AlarmModeBitmap -EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value); + chip::BitMask * value); // AlarmModeBitmap +EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value); } // namespace AlarmsEnabled +namespace AlarmsSupported { +EmberAfStatus Get(chip::EndpointId endpoint, + chip::BitMask * value); // AlarmModeBitmap +EmberAfStatus Set(chip::EndpointId endpoint, chip::BitMask value); +} // namespace AlarmsSupported + +namespace SensorFault { +EmberAfStatus Get(chip::EndpointId endpoint, + chip::BitMask * value); // SensorFaultBitmap +EmberAfStatus Set(chip::EndpointId endpoint, + chip::BitMask value); +} // namespace SensorFault + namespace FeatureMap { EmberAfStatus Get(chip::EndpointId endpoint, uint32_t * value); // bitmap32 EmberAfStatus Set(chip::EndpointId endpoint, uint32_t value); @@ -1857,7 +1879,7 @@ EmberAfStatus Set(chip::EndpointId endpoint, uint16_t value); } // namespace ClusterRevision } // namespace Attributes -} // namespace BooleanSensorConfiguration +} // namespace BooleanStateConfiguration namespace ValveConfigurationAndControl { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 82c757f56a1b31..1f8b6ffcd0eedd 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -537,13 +537,13 @@ void emberAfHepaFilterMonitoringClusterInitCallback(chip::EndpointId endpoint); */ void emberAfActivatedCarbonFilterMonitoringClusterInitCallback(chip::EndpointId endpoint); -/** @brief Boolean Sensor Configuration Cluster Init +/** @brief Boolean State Configuration Cluster Init * * Cluster Init * * @param endpoint Endpoint that is being initialized */ -void emberAfBooleanSensorConfigurationClusterInitCallback(chip::EndpointId endpoint); +void emberAfBooleanStateConfigurationClusterInitCallback(chip::EndpointId endpoint); /** @brief Valve Configuration and Control Cluster Init * @@ -5793,42 +5793,42 @@ void emberAfActivatedCarbonFilterMonitoringClusterServerTickCallback(chip::Endpo void emberAfActivatedCarbonFilterMonitoringClusterClientTickCallback(chip::EndpointId endpoint); // -// Boolean Sensor Configuration Cluster +// Boolean State Configuration Cluster // -/** @brief Boolean Sensor Configuration Cluster Server Init +/** @brief Boolean State Configuration Cluster Server Init * * Server Init * * @param endpoint Endpoint that is being initialized */ -void emberAfBooleanSensorConfigurationClusterServerInitCallback(chip::EndpointId endpoint); +void emberAfBooleanStateConfigurationClusterServerInitCallback(chip::EndpointId endpoint); -/** @brief Boolean Sensor Configuration Cluster Server Shutdown +/** @brief Boolean State Configuration Cluster Server Shutdown * * Server Shutdown * * @param endpoint Endpoint that is being shutdown */ -void MatterBooleanSensorConfigurationClusterServerShutdownCallback(chip::EndpointId endpoint); +void MatterBooleanStateConfigurationClusterServerShutdownCallback(chip::EndpointId endpoint); -/** @brief Boolean Sensor Configuration Cluster Client Init +/** @brief Boolean State Configuration Cluster Client Init * * Client Init * * @param endpoint Endpoint that is being initialized */ -void emberAfBooleanSensorConfigurationClusterClientInitCallback(chip::EndpointId endpoint); +void emberAfBooleanStateConfigurationClusterClientInitCallback(chip::EndpointId endpoint); -/** @brief Boolean Sensor Configuration Cluster Server Attribute Changed +/** @brief Boolean State Configuration Cluster Server Attribute Changed * * Server Attribute Changed * * @param attributePath Concrete attribute path that changed */ -void MatterBooleanSensorConfigurationClusterServerAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath); +void MatterBooleanStateConfigurationClusterServerAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath); -/** @brief Boolean Sensor Configuration Cluster Server Pre Attribute Changed +/** @brief Boolean State Configuration Cluster Server Pre Attribute Changed * * Server Pre Attribute Changed * @@ -5837,10 +5837,10 @@ void MatterBooleanSensorConfigurationClusterServerAttributeChangedCallback(const * @param size Attribute size * @param value Attribute value */ -chip::Protocols::InteractionModel::Status MatterBooleanSensorConfigurationClusterServerPreAttributeChangedCallback( +chip::Protocols::InteractionModel::Status MatterBooleanStateConfigurationClusterServerPreAttributeChangedCallback( const chip::app::ConcreteAttributePath & attributePath, EmberAfAttributeType attributeType, uint16_t size, uint8_t * value); -/** @brief Boolean Sensor Configuration Cluster Client Pre Attribute Changed +/** @brief Boolean State Configuration Cluster Client Pre Attribute Changed * * Client Pre Attribute Changed * @@ -5849,24 +5849,24 @@ chip::Protocols::InteractionModel::Status MatterBooleanSensorConfigurationCluste * @param size Attribute size * @param value Attribute value */ -chip::Protocols::InteractionModel::Status MatterBooleanSensorConfigurationClusterClientPreAttributeChangedCallback( +chip::Protocols::InteractionModel::Status MatterBooleanStateConfigurationClusterClientPreAttributeChangedCallback( const chip::app::ConcreteAttributePath & attributePath, EmberAfAttributeType attributeType, uint16_t size, uint8_t * value); -/** @brief Boolean Sensor Configuration Cluster Server Tick +/** @brief Boolean State Configuration Cluster Server Tick * * Server Tick * * @param endpoint Endpoint that is being served */ -void emberAfBooleanSensorConfigurationClusterServerTickCallback(chip::EndpointId endpoint); +void emberAfBooleanStateConfigurationClusterServerTickCallback(chip::EndpointId endpoint); -/** @brief Boolean Sensor Configuration Cluster Client Tick +/** @brief Boolean State Configuration Cluster Client Tick * * Client Tick * * @param endpoint Endpoint that is being served */ -void emberAfBooleanSensorConfigurationClusterClientTickCallback(chip::EndpointId endpoint); +void emberAfBooleanStateConfigurationClusterClientTickCallback(chip::EndpointId endpoint); // // Valve Configuration and Control Cluster @@ -10097,11 +10097,17 @@ bool emberAfDishwasherAlarmClusterModifyEnabledAlarmsCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::DishwasherAlarm::Commands::ModifyEnabledAlarms::DecodableType & commandData); /** - * @brief Boolean Sensor Configuration Cluster SuppressRequest Command callback (from client) + * @brief Boolean State Configuration Cluster SuppressAlarm Command callback (from client) */ -bool emberAfBooleanSensorConfigurationClusterSuppressRequestCallback( +bool emberAfBooleanStateConfigurationClusterSuppressAlarmCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::BooleanSensorConfiguration::Commands::SuppressRequest::DecodableType & commandData); + const chip::app::Clusters::BooleanStateConfiguration::Commands::SuppressAlarm::DecodableType & commandData); +/** + * @brief Boolean State Configuration Cluster EnableDisableAlarm Command callback (from client) + */ +bool emberAfBooleanStateConfigurationClusterEnableDisableAlarmCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::BooleanStateConfiguration::Commands::EnableDisableAlarm::DecodableType & commandData); /** * @brief Valve Configuration and Control Cluster Open Command callback (from client) */ diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h index 48a2a5094ad527..801a7594706266 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h @@ -1508,20 +1508,6 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(ActivatedCarbonFilterMo } } -static auto __attribute__((unused)) EnsureKnownEnumValue(BooleanSensorConfiguration::SensitivityEnum val) -{ - using EnumType = BooleanSensorConfiguration::SensitivityEnum; - switch (val) - { - case EnumType::kHigh: - case EnumType::kStandard: - case EnumType::kLow: - return val; - default: - return static_cast(3); - } -} - static auto __attribute__((unused)) EnsureKnownEnumValue(ValveConfigurationAndControl::ValveStateEnum val) { using EnumType = ValveConfigurationAndControl::ValveStateEnum; diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index adcca6f89087af..4ad316f2ba3a60 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -2125,20 +2125,7 @@ enum class Feature : uint32_t }; } // namespace ActivatedCarbonFilterMonitoring -namespace BooleanSensorConfiguration { - -// Enum for SensitivityEnum -enum class SensitivityEnum : uint8_t -{ - kHigh = 0x00, - kStandard = 0x01, - kLow = 0x02, - // All received enum values that are not listed above will be mapped - // to kUnknownEnumValue. This is a helper enum value that should only - // be used by code to process how it handles receiving and unknown - // enum value. This specific should never be transmitted. - kUnknownEnumValue = 3, -}; +namespace BooleanStateConfiguration { // Bitmap for AlarmModeBitmap enum class AlarmModeBitmap : uint8_t @@ -2155,7 +2142,13 @@ enum class Feature : uint32_t kAlarmSuppress = 0x4, kSensitivityLevel = 0x8, }; -} // namespace BooleanSensorConfiguration + +// Bitmap for SensorFaultBitmap +enum class SensorFaultBitmap : uint16_t +{ + kGeneralFault = 0x1, +}; +} // namespace BooleanStateConfiguration namespace ValveConfigurationAndControl { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index 99196eceb6effc..dffd9990ba062f 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -13649,10 +13649,10 @@ CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const Concre namespace Events {} // namespace Events } // namespace ActivatedCarbonFilterMonitoring -namespace BooleanSensorConfiguration { +namespace BooleanStateConfiguration { namespace Commands { -namespace SuppressRequest { +namespace SuppressAlarm { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; @@ -13685,7 +13685,41 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) ReturnErrorOnFailure(err); } } -} // namespace SuppressRequest. +} // namespace SuppressAlarm. +namespace EnableDisableAlarm { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kAlarmsToEnableDisable), alarmsToEnableDisable); + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kAlarmsToEnableDisable)) + { + err = DataModel::Decode(reader, alarmsToEnableDisable); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} +} // namespace EnableDisableAlarm. } // namespace Commands namespace Attributes { @@ -13693,14 +13727,22 @@ CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const Concre { switch (path.mAttributeId) { - case Attributes::SensitivityLevel::TypeInfo::GetAttributeId(): - return DataModel::Decode(reader, sensitivityLevel); + case Attributes::CurrentSensitivityLevel::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, currentSensitivityLevel); + case Attributes::SupportedSensitivityLevels::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, supportedSensitivityLevels); + case Attributes::DefaultSensitivityLevel::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, defaultSensitivityLevel); case Attributes::AlarmsActive::TypeInfo::GetAttributeId(): return DataModel::Decode(reader, alarmsActive); case Attributes::AlarmsSuppressed::TypeInfo::GetAttributeId(): return DataModel::Decode(reader, alarmsSuppressed); case Attributes::AlarmsEnabled::TypeInfo::GetAttributeId(): return DataModel::Decode(reader, alarmsEnabled); + case Attributes::AlarmsSupported::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, alarmsSupported); + case Attributes::SensorFault::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, sensorFault); case Attributes::GeneratedCommandList::TypeInfo::GetAttributeId(): return DataModel::Decode(reader, generatedCommandList); case Attributes::AcceptedCommandList::TypeInfo::GetAttributeId(): @@ -13765,6 +13807,7 @@ CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { TLV::TLVType outer; ReturnErrorOnFailure(aWriter.StartContainer(aTag, TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(Fields::kSensorFault), sensorFault)); return aWriter.EndContainer(outer); } @@ -13778,12 +13821,25 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) { return std::get(__element); } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kSensorFault)) + { + err = DataModel::Decode(reader, sensorFault); + } + else + { + } + + ReturnErrorOnFailure(err); } } } // namespace SensorFault. } // namespace Events -} // namespace BooleanSensorConfiguration +} // namespace BooleanStateConfiguration namespace ValveConfigurationAndControl { namespace Commands { @@ -28399,7 +28455,7 @@ bool CommandIsFabricScoped(ClusterId aCluster, CommandId aCommand) return false; } } - case Clusters::BooleanSensorConfiguration::Id: { + case Clusters::BooleanStateConfiguration::Id: { switch (aCommand) { default: diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 7c90c8a9d5a3e1..7f4d3f97dee070 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -19507,20 +19507,25 @@ struct TypeInfo }; } // namespace Attributes } // namespace ActivatedCarbonFilterMonitoring -namespace BooleanSensorConfiguration { +namespace BooleanStateConfiguration { namespace Commands { // Forward-declarations so we can reference these later. -namespace SuppressRequest { +namespace SuppressAlarm { struct Type; struct DecodableType; -} // namespace SuppressRequest +} // namespace SuppressAlarm + +namespace EnableDisableAlarm { +struct Type; +struct DecodableType; +} // namespace EnableDisableAlarm } // namespace Commands namespace Commands { -namespace SuppressRequest { +namespace SuppressAlarm { enum class Fields : uint8_t { kAlarmsToSuppress = 0, @@ -19530,8 +19535,8 @@ struct Type { public: // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand - static constexpr CommandId GetCommandId() { return Commands::SuppressRequest::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr CommandId GetCommandId() { return Commands::SuppressAlarm::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } chip::BitMask alarmsToSuppress = static_cast>(0); @@ -19545,37 +19550,93 @@ struct Type struct DecodableType { public: - static constexpr CommandId GetCommandId() { return Commands::SuppressRequest::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr CommandId GetCommandId() { return Commands::SuppressAlarm::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } chip::BitMask alarmsToSuppress = static_cast>(0); CHIP_ERROR Decode(TLV::TLVReader & reader); }; -}; // namespace SuppressRequest +}; // namespace SuppressAlarm +namespace EnableDisableAlarm { +enum class Fields : uint8_t +{ + kAlarmsToEnableDisable = 0, +}; + +struct Type +{ +public: + // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand + static constexpr CommandId GetCommandId() { return Commands::EnableDisableAlarm::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } + + chip::BitMask alarmsToEnableDisable = static_cast>(0); + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; + + using ResponseType = DataModel::NullObjectType; + + static constexpr bool MustUseTimedInvoke() { return false; } +}; + +struct DecodableType +{ +public: + static constexpr CommandId GetCommandId() { return Commands::EnableDisableAlarm::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } + + chip::BitMask alarmsToEnableDisable = static_cast>(0); + CHIP_ERROR Decode(TLV::TLVReader & reader); +}; +}; // namespace EnableDisableAlarm } // namespace Commands namespace Attributes { -namespace SensitivityLevel { +namespace CurrentSensitivityLevel { struct TypeInfo { - using Type = chip::app::Clusters::BooleanSensorConfiguration::SensitivityEnum; - using DecodableType = chip::app::Clusters::BooleanSensorConfiguration::SensitivityEnum; - using DecodableArgType = chip::app::Clusters::BooleanSensorConfiguration::SensitivityEnum; + using Type = uint8_t; + using DecodableType = uint8_t; + using DecodableArgType = uint8_t; - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } - static constexpr AttributeId GetAttributeId() { return Attributes::SensitivityLevel::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::CurrentSensitivityLevel::Id; } static constexpr bool MustUseTimedWrite() { return false; } }; -} // namespace SensitivityLevel +} // namespace CurrentSensitivityLevel +namespace SupportedSensitivityLevels { +struct TypeInfo +{ + using Type = uint8_t; + using DecodableType = uint8_t; + using DecodableArgType = uint8_t; + + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::SupportedSensitivityLevels::Id; } + static constexpr bool MustUseTimedWrite() { return false; } +}; +} // namespace SupportedSensitivityLevels +namespace DefaultSensitivityLevel { +struct TypeInfo +{ + using Type = uint8_t; + using DecodableType = uint8_t; + using DecodableArgType = uint8_t; + + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::DefaultSensitivityLevel::Id; } + static constexpr bool MustUseTimedWrite() { return false; } +}; +} // namespace DefaultSensitivityLevel namespace AlarmsActive { struct TypeInfo { - using Type = chip::BitMask; - using DecodableType = chip::BitMask; - using DecodableArgType = chip::BitMask; + using Type = chip::BitMask; + using DecodableType = chip::BitMask; + using DecodableArgType = chip::BitMask; - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::AlarmsActive::Id; } static constexpr bool MustUseTimedWrite() { return false; } }; @@ -19583,11 +19644,11 @@ struct TypeInfo namespace AlarmsSuppressed { struct TypeInfo { - using Type = chip::BitMask; - using DecodableType = chip::BitMask; - using DecodableArgType = chip::BitMask; + using Type = chip::BitMask; + using DecodableType = chip::BitMask; + using DecodableArgType = chip::BitMask; - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::AlarmsSuppressed::Id; } static constexpr bool MustUseTimedWrite() { return false; } }; @@ -19595,49 +19656,73 @@ struct TypeInfo namespace AlarmsEnabled { struct TypeInfo { - using Type = chip::BitMask; - using DecodableType = chip::BitMask; - using DecodableArgType = chip::BitMask; + using Type = chip::BitMask; + using DecodableType = chip::BitMask; + using DecodableArgType = chip::BitMask; - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::AlarmsEnabled::Id; } static constexpr bool MustUseTimedWrite() { return false; } }; } // namespace AlarmsEnabled +namespace AlarmsSupported { +struct TypeInfo +{ + using Type = chip::BitMask; + using DecodableType = chip::BitMask; + using DecodableArgType = chip::BitMask; + + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::AlarmsSupported::Id; } + static constexpr bool MustUseTimedWrite() { return false; } +}; +} // namespace AlarmsSupported +namespace SensorFault { +struct TypeInfo +{ + using Type = chip::BitMask; + using DecodableType = chip::BitMask; + using DecodableArgType = chip::BitMask; + + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::SensorFault::Id; } + static constexpr bool MustUseTimedWrite() { return false; } +}; +} // namespace SensorFault namespace GeneratedCommandList { struct TypeInfo : public Clusters::Globals::Attributes::GeneratedCommandList::TypeInfo { - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } }; } // namespace GeneratedCommandList namespace AcceptedCommandList { struct TypeInfo : public Clusters::Globals::Attributes::AcceptedCommandList::TypeInfo { - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } }; } // namespace AcceptedCommandList namespace EventList { struct TypeInfo : public Clusters::Globals::Attributes::EventList::TypeInfo { - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } }; } // namespace EventList namespace AttributeList { struct TypeInfo : public Clusters::Globals::Attributes::AttributeList::TypeInfo { - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } }; } // namespace AttributeList namespace FeatureMap { struct TypeInfo : public Clusters::Globals::Attributes::FeatureMap::TypeInfo { - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } }; } // namespace FeatureMap namespace ClusterRevision { struct TypeInfo : public Clusters::Globals::Attributes::ClusterRevision::TypeInfo { - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } }; } // namespace ClusterRevision @@ -19645,18 +19730,23 @@ struct TypeInfo { struct DecodableType { - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } CHIP_ERROR Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path); - Attributes::SensitivityLevel::TypeInfo::DecodableType sensitivityLevel = - static_cast(0); + Attributes::CurrentSensitivityLevel::TypeInfo::DecodableType currentSensitivityLevel = static_cast(0); + Attributes::SupportedSensitivityLevels::TypeInfo::DecodableType supportedSensitivityLevels = static_cast(0); + Attributes::DefaultSensitivityLevel::TypeInfo::DecodableType defaultSensitivityLevel = static_cast(0); Attributes::AlarmsActive::TypeInfo::DecodableType alarmsActive = - static_cast>(0); + static_cast>(0); Attributes::AlarmsSuppressed::TypeInfo::DecodableType alarmsSuppressed = - static_cast>(0); + static_cast>(0); Attributes::AlarmsEnabled::TypeInfo::DecodableType alarmsEnabled = - static_cast>(0); + static_cast>(0); + Attributes::AlarmsSupported::TypeInfo::DecodableType alarmsSupported = + static_cast>(0); + Attributes::SensorFault::TypeInfo::DecodableType sensorFault = + static_cast>(0); Attributes::GeneratedCommandList::TypeInfo::DecodableType generatedCommandList; Attributes::AcceptedCommandList::TypeInfo::DecodableType acceptedCommandList; Attributes::EventList::TypeInfo::DecodableType eventList; @@ -19681,7 +19771,7 @@ struct Type public: static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } static constexpr EventId GetEventId() { return Events::AlarmsStateChanged::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } static constexpr bool kIsFabricScoped = false; chip::BitMask alarmsActive = static_cast>(0); @@ -19695,7 +19785,7 @@ struct DecodableType public: static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } static constexpr EventId GetEventId() { return Events::AlarmsStateChanged::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } chip::BitMask alarmsActive = static_cast>(0); Optional> alarmsSuppressed; @@ -19708,6 +19798,7 @@ static constexpr PriorityLevel kPriorityLevel = PriorityLevel::Info; enum class Fields : uint8_t { + kSensorFault = 0, }; struct Type @@ -19715,9 +19806,11 @@ struct Type public: static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } static constexpr EventId GetEventId() { return Events::SensorFault::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } static constexpr bool kIsFabricScoped = false; + chip::BitMask sensorFault = static_cast>(0); + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; }; @@ -19726,13 +19819,15 @@ struct DecodableType public: static constexpr PriorityLevel GetPriorityLevel() { return kPriorityLevel; } static constexpr EventId GetEventId() { return Events::SensorFault::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::BooleanSensorConfiguration::Id; } + static constexpr ClusterId GetClusterId() { return Clusters::BooleanStateConfiguration::Id; } + + chip::BitMask sensorFault = static_cast>(0); CHIP_ERROR Decode(TLV::TLVReader & reader); }; } // namespace SensorFault } // namespace Events -} // namespace BooleanSensorConfiguration +} // namespace BooleanStateConfiguration namespace ValveConfigurationAndControl { namespace Commands { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h index 732997cd74bf35..dbd1e568b6e348 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h @@ -3513,25 +3513,41 @@ static constexpr AttributeId Id = Globals::Attributes::ClusterRevision::Id; } // namespace Attributes } // namespace ActivatedCarbonFilterMonitoring -namespace BooleanSensorConfiguration { +namespace BooleanStateConfiguration { namespace Attributes { -namespace SensitivityLevel { +namespace CurrentSensitivityLevel { static constexpr AttributeId Id = 0x00000000; -} // namespace SensitivityLevel +} // namespace CurrentSensitivityLevel -namespace AlarmsActive { +namespace SupportedSensitivityLevels { static constexpr AttributeId Id = 0x00000001; +} // namespace SupportedSensitivityLevels + +namespace DefaultSensitivityLevel { +static constexpr AttributeId Id = 0x00000002; +} // namespace DefaultSensitivityLevel + +namespace AlarmsActive { +static constexpr AttributeId Id = 0x00000003; } // namespace AlarmsActive namespace AlarmsSuppressed { -static constexpr AttributeId Id = 0x00000002; +static constexpr AttributeId Id = 0x00000004; } // namespace AlarmsSuppressed namespace AlarmsEnabled { -static constexpr AttributeId Id = 0x00000003; +static constexpr AttributeId Id = 0x00000005; } // namespace AlarmsEnabled +namespace AlarmsSupported { +static constexpr AttributeId Id = 0x00000006; +} // namespace AlarmsSupported + +namespace SensorFault { +static constexpr AttributeId Id = 0x00000007; +} // namespace SensorFault + namespace GeneratedCommandList { static constexpr AttributeId Id = Globals::Attributes::GeneratedCommandList::Id; } // namespace GeneratedCommandList @@ -3557,7 +3573,7 @@ static constexpr AttributeId Id = Globals::Attributes::ClusterRevision::Id; } // namespace ClusterRevision } // namespace Attributes -} // namespace BooleanSensorConfiguration +} // namespace BooleanStateConfiguration namespace ValveConfigurationAndControl { namespace Attributes { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h b/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h index 30795284640706..3bcd1734de0353 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Clusters.h @@ -214,9 +214,9 @@ static constexpr ClusterId Id = 0x00000071; namespace ActivatedCarbonFilterMonitoring { static constexpr ClusterId Id = 0x00000072; } // namespace ActivatedCarbonFilterMonitoring -namespace BooleanSensorConfiguration { +namespace BooleanStateConfiguration { static constexpr ClusterId Id = 0x00000080; -} // namespace BooleanSensorConfiguration +} // namespace BooleanStateConfiguration namespace ValveConfigurationAndControl { static constexpr ClusterId Id = 0x00000081; } // namespace ValveConfigurationAndControl diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h index 79c4cd73302615..95c4ca8d039278 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h @@ -913,15 +913,19 @@ static constexpr CommandId Id = 0x00000000; } // namespace Commands } // namespace ActivatedCarbonFilterMonitoring -namespace BooleanSensorConfiguration { +namespace BooleanStateConfiguration { namespace Commands { -namespace SuppressRequest { +namespace SuppressAlarm { static constexpr CommandId Id = 0x00000000; -} // namespace SuppressRequest +} // namespace SuppressAlarm + +namespace EnableDisableAlarm { +static constexpr CommandId Id = 0x00000001; +} // namespace EnableDisableAlarm } // namespace Commands -} // namespace BooleanSensorConfiguration +} // namespace BooleanStateConfiguration namespace ValveConfigurationAndControl { namespace Commands { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Events.h b/zzz_generated/app-common/app-common/zap-generated/ids/Events.h index f65f37b9cd13e5..0ea221e713cc6c 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Events.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Events.h @@ -379,7 +379,7 @@ static constexpr EventId Id = 0x00000001; } // namespace Events } // namespace RvcOperationalState -namespace BooleanSensorConfiguration { +namespace BooleanStateConfiguration { namespace Events { namespace AlarmsStateChanged { @@ -391,7 +391,7 @@ static constexpr EventId Id = 0x00000001; } // namespace SensorFault } // namespace Events -} // namespace BooleanSensorConfiguration +} // namespace BooleanStateConfiguration namespace ValveConfigurationAndControl { namespace Events { diff --git a/zzz_generated/app-common/app-common/zap-generated/print-cluster.h b/zzz_generated/app-common/app-common/zap-generated/print-cluster.h index dce92e23194866..a2f0dd80afba47 100644 --- a/zzz_generated/app-common/app-common/zap-generated/print-cluster.h +++ b/zzz_generated/app-common/app-common/zap-generated/print-cluster.h @@ -428,11 +428,11 @@ #define CHIP_PRINTCLUSTER_ACTIVATED_CARBON_FILTER_MONITORING_CLUSTER #endif -#if defined(ZCL_USING_BOOLEAN_SENSOR_CONFIGURATION_CLUSTER_SERVER) || defined(ZCL_USING_BOOLEAN_SENSOR_CONFIGURATION_CLUSTER_CLIENT) -#define CHIP_PRINTCLUSTER_BOOLEAN_SENSOR_CONFIGURATION_CLUSTER \ - { chip::app::Clusters::BooleanSensorConfiguration::Id, "Boolean Sensor Configuration" }, +#if defined(ZCL_USING_BOOLEAN_STATE_CONFIGURATION_CLUSTER_SERVER) || defined(ZCL_USING_BOOLEAN_STATE_CONFIGURATION_CLUSTER_CLIENT) +#define CHIP_PRINTCLUSTER_BOOLEAN_STATE_CONFIGURATION_CLUSTER \ + { chip::app::Clusters::BooleanStateConfiguration::Id, "Boolean State Configuration" }, #else -#define CHIP_PRINTCLUSTER_BOOLEAN_SENSOR_CONFIGURATION_CLUSTER +#define CHIP_PRINTCLUSTER_BOOLEAN_STATE_CONFIGURATION_CLUSTER #endif #if defined(ZCL_USING_VALVE_CONFIGURATION_AND_CONTROL_CLUSTER_SERVER) || \ @@ -823,7 +823,7 @@ CHIP_PRINTCLUSTER_OPERATIONAL_STATE_RVC_CLUSTER \ CHIP_PRINTCLUSTER_HEPA_FILTER_MONITORING_CLUSTER \ CHIP_PRINTCLUSTER_ACTIVATED_CARBON_FILTER_MONITORING_CLUSTER \ - CHIP_PRINTCLUSTER_BOOLEAN_SENSOR_CONFIGURATION_CLUSTER \ + CHIP_PRINTCLUSTER_BOOLEAN_STATE_CONFIGURATION_CLUSTER \ CHIP_PRINTCLUSTER_VALVE_CONFIGURATION_AND_CONTROL_CLUSTER \ CHIP_PRINTCLUSTER_ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER \ CHIP_PRINTCLUSTER_DEMAND_RESPONSE_LOAD_CONTROL_CLUSTER \ diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 0ab3cd79e655bb..1096ae9394d247 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -97,7 +97,7 @@ | RvcOperationalState | 0x0061 | | HepaFilterMonitoring | 0x0071 | | ActivatedCarbonFilterMonitoring | 0x0072 | -| BooleanSensorConfiguration | 0x0080 | +| BooleanStateConfiguration | 0x0080 | | ValveConfigurationAndControl | 0x0081 | | ElectricalEnergyMeasurement | 0x0091 | | DemandResponseLoadControl | 0x0096 | @@ -6371,16 +6371,21 @@ class ActivatedCarbonFilterMonitoringResetCondition : public ClusterCommand }; /*----------------------------------------------------------------------------*\ -| Cluster BooleanSensorConfiguration | 0x0080 | +| Cluster BooleanStateConfiguration | 0x0080 | |------------------------------------------------------------------------------| | Commands: | | -| * SuppressRequest | 0x00 | +| * SuppressAlarm | 0x00 | +| * EnableDisableAlarm | 0x01 | |------------------------------------------------------------------------------| | Attributes: | | -| * SensitivityLevel | 0x0000 | -| * AlarmsActive | 0x0001 | -| * AlarmsSuppressed | 0x0002 | -| * AlarmsEnabled | 0x0003 | +| * CurrentSensitivityLevel | 0x0000 | +| * SupportedSensitivityLevels | 0x0001 | +| * DefaultSensitivityLevel | 0x0002 | +| * AlarmsActive | 0x0003 | +| * AlarmsSuppressed | 0x0004 | +| * AlarmsEnabled | 0x0005 | +| * AlarmsSupported | 0x0006 | +| * SensorFault | 0x0007 | | * GeneratedCommandList | 0xFFF8 | | * AcceptedCommandList | 0xFFF9 | | * EventList | 0xFFFA | @@ -6394,13 +6399,13 @@ class ActivatedCarbonFilterMonitoringResetCondition : public ClusterCommand \*----------------------------------------------------------------------------*/ /* - * Command SuppressRequest + * Command SuppressAlarm */ -class BooleanSensorConfigurationSuppressRequest : public ClusterCommand +class BooleanStateConfigurationSuppressAlarm : public ClusterCommand { public: - BooleanSensorConfigurationSuppressRequest(CredentialIssuerCommands * credsIssuerConfig) : - ClusterCommand("suppress-request", credsIssuerConfig) + BooleanStateConfigurationSuppressAlarm(CredentialIssuerCommands * credsIssuerConfig) : + ClusterCommand("suppress-alarm", credsIssuerConfig) { AddArgument("AlarmsToSuppress", 0, UINT8_MAX, &mRequest.alarmsToSuppress); ClusterCommand::AddArguments(); @@ -6408,8 +6413,8 @@ class BooleanSensorConfigurationSuppressRequest : public ClusterCommand CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::BooleanSensorConfiguration::Commands::SuppressRequest::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::BooleanStateConfiguration::Commands::SuppressAlarm::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointIds.at(0)); @@ -6418,8 +6423,8 @@ class BooleanSensorConfigurationSuppressRequest : public ClusterCommand CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::BooleanSensorConfiguration::Commands::SuppressRequest::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::BooleanStateConfiguration::Commands::SuppressAlarm::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, groupId); @@ -6428,7 +6433,45 @@ class BooleanSensorConfigurationSuppressRequest : public ClusterCommand } private: - chip::app::Clusters::BooleanSensorConfiguration::Commands::SuppressRequest::Type mRequest; + chip::app::Clusters::BooleanStateConfiguration::Commands::SuppressAlarm::Type mRequest; +}; + +/* + * Command EnableDisableAlarm + */ +class BooleanStateConfigurationEnableDisableAlarm : public ClusterCommand +{ +public: + BooleanStateConfigurationEnableDisableAlarm(CredentialIssuerCommands * credsIssuerConfig) : + ClusterCommand("enable-disable-alarm", credsIssuerConfig) + { + AddArgument("AlarmsToEnableDisable", 0, UINT8_MAX, &mRequest.alarmsToEnableDisable); + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::BooleanStateConfiguration::Commands::EnableDisableAlarm::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, + commandId, endpointIds.at(0)); + return ClusterCommand::SendCommand(device, endpointIds.at(0), clusterId, commandId, mRequest); + } + + CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::BooleanStateConfiguration::Commands::EnableDisableAlarm::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, + groupId); + + return ClusterCommand::SendGroupCommand(groupId, fabricIndex, clusterId, commandId, mRequest); + } + +private: + chip::app::Clusters::BooleanStateConfiguration::Commands::EnableDisableAlarm::Type mRequest; }; /*----------------------------------------------------------------------------*\ @@ -19173,43 +19216,58 @@ void registerClusterActivatedCarbonFilterMonitoring(Commands & commands, Credent commands.RegisterCluster(clusterName, clusterCommands); } -void registerClusterBooleanSensorConfiguration(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) +void registerClusterBooleanStateConfiguration(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) { - using namespace chip::app::Clusters::BooleanSensorConfiguration; + using namespace chip::app::Clusters::BooleanStateConfiguration; - const char * clusterName = "BooleanSensorConfiguration"; + const char * clusterName = "BooleanStateConfiguration"; commands_list clusterCommands = { // // Commands // - make_unique(Id, credsIssuerConfig), // - make_unique(credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(credsIssuerConfig), // + make_unique(credsIssuerConfig), // // // Attributes // - make_unique(Id, credsIssuerConfig), // - make_unique(Id, "sensitivity-level", Attributes::SensitivityLevel::Id, credsIssuerConfig), // - make_unique(Id, "alarms-active", Attributes::AlarmsActive::Id, credsIssuerConfig), // - make_unique(Id, "alarms-suppressed", Attributes::AlarmsSuppressed::Id, credsIssuerConfig), // - make_unique(Id, "alarms-enabled", Attributes::AlarmsEnabled::Id, credsIssuerConfig), // - make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // - make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // - make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // - make_unique(Id, "attribute-list", Attributes::AttributeList::Id, credsIssuerConfig), // - make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // - make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // - make_unique>(Id, credsIssuerConfig), // - make_unique>( - Id, "sensitivity-level", 0, UINT8_MAX, Attributes::SensitivityLevel::Id, WriteCommandType::kWrite, - credsIssuerConfig), // - make_unique>>( + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "current-sensitivity-level", Attributes::CurrentSensitivityLevel::Id, credsIssuerConfig), // + make_unique(Id, "supported-sensitivity-levels", Attributes::SupportedSensitivityLevels::Id, + credsIssuerConfig), // + make_unique(Id, "default-sensitivity-level", Attributes::DefaultSensitivityLevel::Id, credsIssuerConfig), // + make_unique(Id, "alarms-active", Attributes::AlarmsActive::Id, credsIssuerConfig), // + make_unique(Id, "alarms-suppressed", Attributes::AlarmsSuppressed::Id, credsIssuerConfig), // + make_unique(Id, "alarms-enabled", Attributes::AlarmsEnabled::Id, credsIssuerConfig), // + make_unique(Id, "alarms-supported", Attributes::AlarmsSupported::Id, credsIssuerConfig), // + make_unique(Id, "sensor-fault", Attributes::SensorFault::Id, credsIssuerConfig), // + make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // + make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // + make_unique(Id, "attribute-list", Attributes::AttributeList::Id, credsIssuerConfig), // + make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // + make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // + make_unique>(Id, credsIssuerConfig), // + make_unique>(Id, "current-sensitivity-level", 0, UINT8_MAX, Attributes::CurrentSensitivityLevel::Id, + WriteCommandType::kWrite, credsIssuerConfig), // + make_unique>(Id, "supported-sensitivity-levels", 0, UINT8_MAX, + Attributes::SupportedSensitivityLevels::Id, WriteCommandType::kForceWrite, + credsIssuerConfig), // + make_unique>(Id, "default-sensitivity-level", 0, UINT8_MAX, Attributes::DefaultSensitivityLevel::Id, + WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( Id, "alarms-active", 0, UINT8_MAX, Attributes::AlarmsActive::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>( + make_unique>>( Id, "alarms-suppressed", 0, UINT8_MAX, Attributes::AlarmsSuppressed::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>( - Id, "alarms-enabled", 0, UINT8_MAX, Attributes::AlarmsEnabled::Id, WriteCommandType::kWrite, credsIssuerConfig), // + make_unique>>( + Id, "alarms-enabled", 0, UINT8_MAX, Attributes::AlarmsEnabled::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "alarms-supported", 0, UINT8_MAX, Attributes::AlarmsSupported::Id, WriteCommandType::kForceWrite, + credsIssuerConfig), // + make_unique>>( + Id, "sensor-fault", 0, UINT16_MAX, Attributes::SensorFault::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>( Id, "generated-command-list", Attributes::GeneratedCommandList::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // @@ -19222,12 +19280,19 @@ void registerClusterBooleanSensorConfiguration(Commands & commands, CredentialIs make_unique>(Id, "feature-map", 0, UINT32_MAX, Attributes::FeatureMap::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>(Id, "cluster-revision", 0, UINT16_MAX, Attributes::ClusterRevision::Id, - WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique(Id, credsIssuerConfig), // - make_unique(Id, "sensitivity-level", Attributes::SensitivityLevel::Id, credsIssuerConfig), // + WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(Id, "current-sensitivity-level", Attributes::CurrentSensitivityLevel::Id, + credsIssuerConfig), // + make_unique(Id, "supported-sensitivity-levels", Attributes::SupportedSensitivityLevels::Id, + credsIssuerConfig), // + make_unique(Id, "default-sensitivity-level", Attributes::DefaultSensitivityLevel::Id, + credsIssuerConfig), // make_unique(Id, "alarms-active", Attributes::AlarmsActive::Id, credsIssuerConfig), // make_unique(Id, "alarms-suppressed", Attributes::AlarmsSuppressed::Id, credsIssuerConfig), // make_unique(Id, "alarms-enabled", Attributes::AlarmsEnabled::Id, credsIssuerConfig), // + make_unique(Id, "alarms-supported", Attributes::AlarmsSupported::Id, credsIssuerConfig), // + make_unique(Id, "sensor-fault", Attributes::SensorFault::Id, credsIssuerConfig), // make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // make_unique(Id, "accepted-command-list", Attributes::AcceptedCommandList::Id, credsIssuerConfig), // make_unique(Id, "event-list", Attributes::EventList::Id, credsIssuerConfig), // @@ -25382,7 +25447,7 @@ void registerClusters(Commands & commands, CredentialIssuerCommands * credsIssue registerClusterRvcOperationalState(commands, credsIssuerConfig); registerClusterHepaFilterMonitoring(commands, credsIssuerConfig); registerClusterActivatedCarbonFilterMonitoring(commands, credsIssuerConfig); - registerClusterBooleanSensorConfiguration(commands, credsIssuerConfig); + registerClusterBooleanStateConfiguration(commands, credsIssuerConfig); registerClusterValveConfigurationAndControl(commands, credsIssuerConfig); registerClusterElectricalEnergyMeasurement(commands, credsIssuerConfig); registerClusterDemandResponseLoadControl(commands, credsIssuerConfig); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index 6a56a914177981..86c899d49d69a2 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -5481,7 +5481,7 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, - const BooleanSensorConfiguration::Events::AlarmsStateChanged::DecodableType & value) + const BooleanStateConfiguration::Events::AlarmsStateChanged::DecodableType & value) { DataModelLogger::LogString(label, indent, "{"); { @@ -5505,9 +5505,17 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, - const BooleanSensorConfiguration::Events::SensorFault::DecodableType & value) + const BooleanStateConfiguration::Events::SensorFault::DecodableType & value) { DataModelLogger::LogString(label, indent, "{"); + { + CHIP_ERROR err = DataModelLogger::LogValue("SensorFault", indent + 1, value.sensorFault); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Event truncated due to invalid value for 'SensorFault'"); + return err; + } + } DataModelLogger::LogString(indent, "}"); return CHIP_NO_ERROR; @@ -11550,55 +11558,75 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP } break; } - case BooleanSensorConfiguration::Id: { + case BooleanStateConfiguration::Id: { switch (path.mAttributeId) { - case BooleanSensorConfiguration::Attributes::SensitivityLevel::Id: { - chip::app::Clusters::BooleanSensorConfiguration::SensitivityEnum value; + case BooleanStateConfiguration::Attributes::CurrentSensitivityLevel::Id: { + uint8_t value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("CurrentSensitivityLevel", 1, value); + } + case BooleanStateConfiguration::Attributes::SupportedSensitivityLevels::Id: { + uint8_t value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); - return DataModelLogger::LogValue("SensitivityLevel", 1, value); + return DataModelLogger::LogValue("SupportedSensitivityLevels", 1, value); } - case BooleanSensorConfiguration::Attributes::AlarmsActive::Id: { - chip::BitMask value; + case BooleanStateConfiguration::Attributes::DefaultSensitivityLevel::Id: { + uint8_t value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("DefaultSensitivityLevel", 1, value); + } + case BooleanStateConfiguration::Attributes::AlarmsActive::Id: { + chip::BitMask value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("AlarmsActive", 1, value); } - case BooleanSensorConfiguration::Attributes::AlarmsSuppressed::Id: { - chip::BitMask value; + case BooleanStateConfiguration::Attributes::AlarmsSuppressed::Id: { + chip::BitMask value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("AlarmsSuppressed", 1, value); } - case BooleanSensorConfiguration::Attributes::AlarmsEnabled::Id: { - chip::BitMask value; + case BooleanStateConfiguration::Attributes::AlarmsEnabled::Id: { + chip::BitMask value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("AlarmsEnabled", 1, value); } - case BooleanSensorConfiguration::Attributes::GeneratedCommandList::Id: { + case BooleanStateConfiguration::Attributes::AlarmsSupported::Id: { + chip::BitMask value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("AlarmsSupported", 1, value); + } + case BooleanStateConfiguration::Attributes::SensorFault::Id: { + chip::BitMask value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("SensorFault", 1, value); + } + case BooleanStateConfiguration::Attributes::GeneratedCommandList::Id: { chip::app::DataModel::DecodableList value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("GeneratedCommandList", 1, value); } - case BooleanSensorConfiguration::Attributes::AcceptedCommandList::Id: { + case BooleanStateConfiguration::Attributes::AcceptedCommandList::Id: { chip::app::DataModel::DecodableList value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("AcceptedCommandList", 1, value); } - case BooleanSensorConfiguration::Attributes::EventList::Id: { + case BooleanStateConfiguration::Attributes::EventList::Id: { chip::app::DataModel::DecodableList value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("EventList", 1, value); } - case BooleanSensorConfiguration::Attributes::AttributeList::Id: { + case BooleanStateConfiguration::Attributes::AttributeList::Id: { chip::app::DataModel::DecodableList value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("AttributeList", 1, value); } - case BooleanSensorConfiguration::Attributes::FeatureMap::Id: { + case BooleanStateConfiguration::Attributes::FeatureMap::Id: { uint32_t value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("FeatureMap", 1, value); } - case BooleanSensorConfiguration::Attributes::ClusterRevision::Id: { + case BooleanStateConfiguration::Attributes::ClusterRevision::Id: { uint16_t value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("ClusterRevision", 1, value); @@ -17796,16 +17824,16 @@ CHIP_ERROR DataModelLogger::LogEvent(const chip::app::EventHeader & header, chip } break; } - case BooleanSensorConfiguration::Id: { + case BooleanStateConfiguration::Id: { switch (header.mPath.mEventId) { - case BooleanSensorConfiguration::Events::AlarmsStateChanged::Id: { - chip::app::Clusters::BooleanSensorConfiguration::Events::AlarmsStateChanged::DecodableType value; + case BooleanStateConfiguration::Events::AlarmsStateChanged::Id: { + chip::app::Clusters::BooleanStateConfiguration::Events::AlarmsStateChanged::DecodableType value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("AlarmsStateChanged", 1, value); } - case BooleanSensorConfiguration::Events::SensorFault::Id: { - chip::app::Clusters::BooleanSensorConfiguration::Events::SensorFault::DecodableType value; + case BooleanStateConfiguration::Events::SensorFault::Id: { + chip::app::Clusters::BooleanStateConfiguration::Events::SensorFault::DecodableType value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("SensorFault", 1, value); } diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h index c208cac4302149..d768721f46c0fc 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h @@ -462,11 +462,10 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::RvcOperationalState::Events::OperationalError::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::RvcOperationalState::Events::OperationCompletion::DecodableType & value); -static CHIP_ERROR -LogValue(const char * label, size_t indent, - const chip::app::Clusters::BooleanSensorConfiguration::Events::AlarmsStateChanged::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, - const chip::app::Clusters::BooleanSensorConfiguration::Events::SensorFault::DecodableType & value); + const chip::app::Clusters::BooleanStateConfiguration::Events::AlarmsStateChanged::DecodableType & value); +static CHIP_ERROR LogValue(const char * label, size_t indent, + const chip::app::Clusters::BooleanStateConfiguration::Events::SensorFault::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::ValveConfigurationAndControl::Events::ValveStateChanged::DecodableType & value); diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index ee479487347d1b..15336c55a565c9 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -100,7 +100,7 @@ | RvcOperationalState | 0x0061 | | HepaFilterMonitoring | 0x0071 | | ActivatedCarbonFilterMonitoring | 0x0072 | -| BooleanSensorConfiguration | 0x0080 | +| BooleanStateConfiguration | 0x0080 | | ValveConfigurationAndControl | 0x0081 | | ElectricalEnergyMeasurement | 0x0091 | | DemandResponseLoadControl | 0x0096 | @@ -73269,16 +73269,21 @@ class SubscribeAttributeActivatedCarbonFilterMonitoringClusterRevision : public #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL /*----------------------------------------------------------------------------*\ -| Cluster BooleanSensorConfiguration | 0x0080 | +| Cluster BooleanStateConfiguration | 0x0080 | |------------------------------------------------------------------------------| | Commands: | | -| * SuppressRequest | 0x00 | +| * SuppressAlarm | 0x00 | +| * EnableDisableAlarm | 0x01 | |------------------------------------------------------------------------------| | Attributes: | | -| * SensitivityLevel | 0x0000 | -| * AlarmsActive | 0x0001 | -| * AlarmsSuppressed | 0x0002 | -| * AlarmsEnabled | 0x0003 | +| * CurrentSensitivityLevel | 0x0000 | +| * SupportedSensitivityLevels | 0x0001 | +| * DefaultSensitivityLevel | 0x0002 | +| * AlarmsActive | 0x0003 | +| * AlarmsSuppressed | 0x0004 | +| * AlarmsEnabled | 0x0005 | +| * AlarmsSupported | 0x0006 | +| * SensorFault | 0x0007 | | * GeneratedCommandList | 0xFFF8 | | * AcceptedCommandList | 0xFFF9 | | * EventList | 0xFFFA | @@ -73293,12 +73298,12 @@ class SubscribeAttributeActivatedCarbonFilterMonitoringClusterRevision : public #if MTR_ENABLE_PROVISIONAL /* - * Command SuppressRequest + * Command SuppressAlarm */ -class BooleanSensorConfigurationSuppressRequest : public ClusterCommand { +class BooleanStateConfigurationSuppressAlarm : public ClusterCommand { public: - BooleanSensorConfigurationSuppressRequest() - : ClusterCommand("suppress-request") + BooleanStateConfigurationSuppressAlarm() + : ClusterCommand("suppress-alarm") { #if MTR_ENABLE_PROVISIONAL AddArgument("AlarmsToSuppress", 0, UINT8_MAX, &mRequest.alarmsToSuppress); @@ -73308,14 +73313,14 @@ class BooleanSensorConfigurationSuppressRequest : public ClusterCommand { CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::BooleanSensorConfiguration::Commands::SuppressRequest::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::BooleanStateConfiguration::Commands::SuppressAlarm::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - __auto_type * params = [[MTRBooleanSensorConfigurationClusterSuppressRequestParams alloc] init]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRBooleanStateConfigurationClusterSuppressAlarmParams alloc] init]; params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; #if MTR_ENABLE_PROVISIONAL params.alarmsToSuppress = [NSNumber numberWithUnsignedChar:mRequest.alarmsToSuppress.Raw()]; @@ -73323,24 +73328,77 @@ class BooleanSensorConfigurationSuppressRequest : public ClusterCommand { uint16_t repeatCount = mRepeatCount.ValueOr(1); uint16_t __block responsesNeeded = repeatCount; while (repeatCount--) { - [cluster suppressRequestWithParams:params completion: - ^(NSError * _Nullable error) { - responsesNeeded--; - if (error != nil) { - mError = error; - LogNSError("Error", error); - RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(commandId), error); - } - if (responsesNeeded == 0) { - SetCommandExitStatus(mError); - } - }]; + [cluster suppressAlarmWithParams:params completion: + ^(NSError * _Nullable error) { + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(commandId), error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; + } + return CHIP_NO_ERROR; + } + +private: + chip::app::Clusters::BooleanStateConfiguration::Commands::SuppressAlarm::Type mRequest; +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL +/* + * Command EnableDisableAlarm + */ +class BooleanStateConfigurationEnableDisableAlarm : public ClusterCommand { +public: + BooleanStateConfigurationEnableDisableAlarm() + : ClusterCommand("enable-disable-alarm") + { +#if MTR_ENABLE_PROVISIONAL + AddArgument("AlarmsToEnableDisable", 0, UINT8_MAX, &mRequest.alarmsToEnableDisable); +#endif // MTR_ENABLE_PROVISIONAL + ClusterCommand::AddArguments(); + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::BooleanStateConfiguration::Commands::EnableDisableAlarm::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRBooleanStateConfigurationClusterEnableDisableAlarmParams alloc] init]; + params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; +#if MTR_ENABLE_PROVISIONAL + params.alarmsToEnableDisable = [NSNumber numberWithUnsignedChar:mRequest.alarmsToEnableDisable.Raw()]; +#endif // MTR_ENABLE_PROVISIONAL + uint16_t repeatCount = mRepeatCount.ValueOr(1); + uint16_t __block responsesNeeded = repeatCount; + while (repeatCount--) { + [cluster enableDisableAlarmWithParams:params completion: + ^(NSError * _Nullable error) { + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(commandId), error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; } return CHIP_NO_ERROR; } private: - chip::app::Clusters::BooleanSensorConfiguration::Commands::SuppressRequest::Type mRequest; + chip::app::Clusters::BooleanStateConfiguration::Commands::EnableDisableAlarm::Type mRequest; }; #endif // MTR_ENABLE_PROVISIONAL @@ -73348,34 +73406,34 @@ class BooleanSensorConfigurationSuppressRequest : public ClusterCommand { #if MTR_ENABLE_PROVISIONAL /* - * Attribute SensitivityLevel + * Attribute CurrentSensitivityLevel */ -class ReadBooleanSensorConfigurationSensitivityLevel : public ReadAttribute { +class ReadBooleanStateConfigurationCurrentSensitivityLevel : public ReadAttribute { public: - ReadBooleanSensorConfigurationSensitivityLevel() - : ReadAttribute("sensitivity-level") + ReadBooleanStateConfigurationCurrentSensitivityLevel() + : ReadAttribute("current-sensitivity-level") { } - ~ReadBooleanSensorConfigurationSensitivityLevel() + ~ReadBooleanStateConfigurationCurrentSensitivityLevel() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::SensitivityLevel::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::CurrentSensitivityLevel::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - [cluster readAttributeSensitivityLevelWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.SensitivityLevel response %@", [value description]); + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeCurrentSensitivityLevelWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"BooleanStateConfiguration.CurrentSensitivityLevel response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration SensitivityLevel read Error", error); + LogNSError("BooleanStateConfiguration CurrentSensitivityLevel read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -73384,36 +73442,36 @@ class ReadBooleanSensorConfigurationSensitivityLevel : public ReadAttribute { } }; -class WriteBooleanSensorConfigurationSensitivityLevel : public WriteAttribute { +class WriteBooleanStateConfigurationCurrentSensitivityLevel : public WriteAttribute { public: - WriteBooleanSensorConfigurationSensitivityLevel() - : WriteAttribute("sensitivity-level") + WriteBooleanStateConfigurationCurrentSensitivityLevel() + : WriteAttribute("current-sensitivity-level") { - AddArgument("attr-name", "sensitivity-level"); + AddArgument("attr-name", "current-sensitivity-level"); AddArgument("attr-value", 0, UINT8_MAX, &mValue); WriteAttribute::AddArguments(); } - ~WriteBooleanSensorConfigurationSensitivityLevel() + ~WriteBooleanStateConfigurationCurrentSensitivityLevel() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::SensitivityLevel::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::CurrentSensitivityLevel::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") WriteAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRWriteParams alloc] init]; params.timedWriteTimeout = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; params.dataVersion = mDataVersion.HasValue() ? [NSNumber numberWithUnsignedInt:mDataVersion.Value()] : nil; NSNumber * _Nonnull value = [NSNumber numberWithUnsignedChar:mValue]; - [cluster writeAttributeSensitivityLevelWithValue:value params:params completion:^(NSError * _Nullable error) { + [cluster writeAttributeCurrentSensitivityLevelWithValue:value params:params completion:^(NSError * _Nullable error) { if (error != nil) { - LogNSError("BooleanSensorConfiguration SensitivityLevel write Error", error); + LogNSError("BooleanStateConfiguration CurrentSensitivityLevel write Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -73425,25 +73483,195 @@ class WriteBooleanSensorConfigurationSensitivityLevel : public WriteAttribute { uint8_t mValue; }; -class SubscribeAttributeBooleanSensorConfigurationSensitivityLevel : public SubscribeAttribute { +class SubscribeAttributeBooleanStateConfigurationCurrentSensitivityLevel : public SubscribeAttribute { +public: + SubscribeAttributeBooleanStateConfigurationCurrentSensitivityLevel() + : SubscribeAttribute("current-sensitivity-level") + { + } + + ~SubscribeAttributeBooleanStateConfigurationCurrentSensitivityLevel() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::CurrentSensitivityLevel::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeCurrentSensitivityLevelWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"BooleanStateConfiguration.CurrentSensitivityLevel response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute SupportedSensitivityLevels + */ +class ReadBooleanStateConfigurationSupportedSensitivityLevels : public ReadAttribute { +public: + ReadBooleanStateConfigurationSupportedSensitivityLevels() + : ReadAttribute("supported-sensitivity-levels") + { + } + + ~ReadBooleanStateConfigurationSupportedSensitivityLevels() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::SupportedSensitivityLevels::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeSupportedSensitivityLevelsWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"BooleanStateConfiguration.SupportedSensitivityLevels response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("BooleanStateConfiguration SupportedSensitivityLevels read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeBooleanStateConfigurationSupportedSensitivityLevels : public SubscribeAttribute { +public: + SubscribeAttributeBooleanStateConfigurationSupportedSensitivityLevels() + : SubscribeAttribute("supported-sensitivity-levels") + { + } + + ~SubscribeAttributeBooleanStateConfigurationSupportedSensitivityLevels() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::SupportedSensitivityLevels::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeSupportedSensitivityLevelsWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"BooleanStateConfiguration.SupportedSensitivityLevels response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute DefaultSensitivityLevel + */ +class ReadBooleanStateConfigurationDefaultSensitivityLevel : public ReadAttribute { public: - SubscribeAttributeBooleanSensorConfigurationSensitivityLevel() - : SubscribeAttribute("sensitivity-level") + ReadBooleanStateConfigurationDefaultSensitivityLevel() + : ReadAttribute("default-sensitivity-level") { } - ~SubscribeAttributeBooleanSensorConfigurationSensitivityLevel() + ~ReadBooleanStateConfigurationDefaultSensitivityLevel() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::SensitivityLevel::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::DefaultSensitivityLevel::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeDefaultSensitivityLevelWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"BooleanStateConfiguration.DefaultSensitivityLevel response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("BooleanStateConfiguration DefaultSensitivityLevel read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeBooleanStateConfigurationDefaultSensitivityLevel : public SubscribeAttribute { +public: + SubscribeAttributeBooleanStateConfigurationDefaultSensitivityLevel() + : SubscribeAttribute("default-sensitivity-level") + { + } + + ~SubscribeAttributeBooleanStateConfigurationDefaultSensitivityLevel() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::DefaultSensitivityLevel::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -73454,10 +73682,10 @@ class SubscribeAttributeBooleanSensorConfigurationSensitivityLevel : public Subs if (mAutoResubscribe.HasValue()) { params.resubscribeAutomatically = mAutoResubscribe.Value(); } - [cluster subscribeAttributeSensitivityLevelWithParams:params + [cluster subscribeAttributeDefaultSensitivityLevelWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.SensitivityLevel response %@", [value description]); + NSLog(@"BooleanStateConfiguration.DefaultSensitivityLevel response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -73476,32 +73704,32 @@ class SubscribeAttributeBooleanSensorConfigurationSensitivityLevel : public Subs /* * Attribute AlarmsActive */ -class ReadBooleanSensorConfigurationAlarmsActive : public ReadAttribute { +class ReadBooleanStateConfigurationAlarmsActive : public ReadAttribute { public: - ReadBooleanSensorConfigurationAlarmsActive() + ReadBooleanStateConfigurationAlarmsActive() : ReadAttribute("alarms-active") { } - ~ReadBooleanSensorConfigurationAlarmsActive() + ~ReadBooleanStateConfigurationAlarmsActive() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AlarmsActive::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AlarmsActive::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; [cluster readAttributeAlarmsActiveWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AlarmsActive response %@", [value description]); + NSLog(@"BooleanStateConfiguration.AlarmsActive response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration AlarmsActive read Error", error); + LogNSError("BooleanStateConfiguration AlarmsActive read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -73510,25 +73738,25 @@ class ReadBooleanSensorConfigurationAlarmsActive : public ReadAttribute { } }; -class SubscribeAttributeBooleanSensorConfigurationAlarmsActive : public SubscribeAttribute { +class SubscribeAttributeBooleanStateConfigurationAlarmsActive : public SubscribeAttribute { public: - SubscribeAttributeBooleanSensorConfigurationAlarmsActive() + SubscribeAttributeBooleanStateConfigurationAlarmsActive() : SubscribeAttribute("alarms-active") { } - ~SubscribeAttributeBooleanSensorConfigurationAlarmsActive() + ~SubscribeAttributeBooleanStateConfigurationAlarmsActive() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AlarmsActive::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AlarmsActive::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -73542,7 +73770,7 @@ class SubscribeAttributeBooleanSensorConfigurationAlarmsActive : public Subscrib [cluster subscribeAttributeAlarmsActiveWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AlarmsActive response %@", [value description]); + NSLog(@"BooleanStateConfiguration.AlarmsActive response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -73561,32 +73789,32 @@ class SubscribeAttributeBooleanSensorConfigurationAlarmsActive : public Subscrib /* * Attribute AlarmsSuppressed */ -class ReadBooleanSensorConfigurationAlarmsSuppressed : public ReadAttribute { +class ReadBooleanStateConfigurationAlarmsSuppressed : public ReadAttribute { public: - ReadBooleanSensorConfigurationAlarmsSuppressed() + ReadBooleanStateConfigurationAlarmsSuppressed() : ReadAttribute("alarms-suppressed") { } - ~ReadBooleanSensorConfigurationAlarmsSuppressed() + ~ReadBooleanStateConfigurationAlarmsSuppressed() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AlarmsSuppressed::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AlarmsSuppressed::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; [cluster readAttributeAlarmsSuppressedWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AlarmsSuppressed response %@", [value description]); + NSLog(@"BooleanStateConfiguration.AlarmsSuppressed response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration AlarmsSuppressed read Error", error); + LogNSError("BooleanStateConfiguration AlarmsSuppressed read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -73595,25 +73823,25 @@ class ReadBooleanSensorConfigurationAlarmsSuppressed : public ReadAttribute { } }; -class SubscribeAttributeBooleanSensorConfigurationAlarmsSuppressed : public SubscribeAttribute { +class SubscribeAttributeBooleanStateConfigurationAlarmsSuppressed : public SubscribeAttribute { public: - SubscribeAttributeBooleanSensorConfigurationAlarmsSuppressed() + SubscribeAttributeBooleanStateConfigurationAlarmsSuppressed() : SubscribeAttribute("alarms-suppressed") { } - ~SubscribeAttributeBooleanSensorConfigurationAlarmsSuppressed() + ~SubscribeAttributeBooleanStateConfigurationAlarmsSuppressed() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AlarmsSuppressed::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AlarmsSuppressed::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -73627,7 +73855,7 @@ class SubscribeAttributeBooleanSensorConfigurationAlarmsSuppressed : public Subs [cluster subscribeAttributeAlarmsSuppressedWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AlarmsSuppressed response %@", [value description]); + NSLog(@"BooleanStateConfiguration.AlarmsSuppressed response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -73646,32 +73874,32 @@ class SubscribeAttributeBooleanSensorConfigurationAlarmsSuppressed : public Subs /* * Attribute AlarmsEnabled */ -class ReadBooleanSensorConfigurationAlarmsEnabled : public ReadAttribute { +class ReadBooleanStateConfigurationAlarmsEnabled : public ReadAttribute { public: - ReadBooleanSensorConfigurationAlarmsEnabled() + ReadBooleanStateConfigurationAlarmsEnabled() : ReadAttribute("alarms-enabled") { } - ~ReadBooleanSensorConfigurationAlarmsEnabled() + ~ReadBooleanStateConfigurationAlarmsEnabled() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AlarmsEnabled::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AlarmsEnabled::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; [cluster readAttributeAlarmsEnabledWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AlarmsEnabled response %@", [value description]); + NSLog(@"BooleanStateConfiguration.AlarmsEnabled response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration AlarmsEnabled read Error", error); + LogNSError("BooleanStateConfiguration AlarmsEnabled read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -73680,66 +73908,195 @@ class ReadBooleanSensorConfigurationAlarmsEnabled : public ReadAttribute { } }; -class WriteBooleanSensorConfigurationAlarmsEnabled : public WriteAttribute { +class SubscribeAttributeBooleanStateConfigurationAlarmsEnabled : public SubscribeAttribute { public: - WriteBooleanSensorConfigurationAlarmsEnabled() - : WriteAttribute("alarms-enabled") + SubscribeAttributeBooleanStateConfigurationAlarmsEnabled() + : SubscribeAttribute("alarms-enabled") { - AddArgument("attr-name", "alarms-enabled"); - AddArgument("attr-value", 0, UINT8_MAX, &mValue); - WriteAttribute::AddArguments(); } - ~WriteBooleanSensorConfigurationAlarmsEnabled() + ~SubscribeAttributeBooleanStateConfigurationAlarmsEnabled() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AlarmsEnabled::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AlarmsEnabled::Id; - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") WriteAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - __auto_type * params = [[MTRWriteParams alloc] init]; - params.timedWriteTimeout = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; - params.dataVersion = mDataVersion.HasValue() ? [NSNumber numberWithUnsignedInt:mDataVersion.Value()] : nil; - NSNumber * _Nonnull value = [NSNumber numberWithUnsignedChar:mValue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeAlarmsEnabledWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"BooleanStateConfiguration.AlarmsEnabled response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; - [cluster writeAttributeAlarmsEnabledWithValue:value params:params completion:^(NSError * _Nullable error) { - if (error != nil) { - LogNSError("BooleanSensorConfiguration AlarmsEnabled write Error", error); + return CHIP_NO_ERROR; + } +}; + +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute AlarmsSupported + */ +class ReadBooleanStateConfigurationAlarmsSupported : public ReadAttribute { +public: + ReadBooleanStateConfigurationAlarmsSupported() + : ReadAttribute("alarms-supported") + { + } + + ~ReadBooleanStateConfigurationAlarmsSupported() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AlarmsSupported::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeAlarmsSupportedWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"BooleanStateConfiguration.AlarmsSupported response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("BooleanStateConfiguration AlarmsSupported read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); }]; return CHIP_NO_ERROR; } +}; -private: - uint8_t mValue; +class SubscribeAttributeBooleanStateConfigurationAlarmsSupported : public SubscribeAttribute { +public: + SubscribeAttributeBooleanStateConfigurationAlarmsSupported() + : SubscribeAttribute("alarms-supported") + { + } + + ~SubscribeAttributeBooleanStateConfigurationAlarmsSupported() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AlarmsSupported::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; + if (mKeepSubscriptions.HasValue()) { + params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); + } + if (mFabricFiltered.HasValue()) { + params.filterByFabric = mFabricFiltered.Value(); + } + if (mAutoResubscribe.HasValue()) { + params.resubscribeAutomatically = mAutoResubscribe.Value(); + } + [cluster subscribeAttributeAlarmsSupportedWithParams:params + subscriptionEstablished:^() { mSubscriptionEstablished = YES; } + reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"BooleanStateConfiguration.AlarmsSupported response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + + return CHIP_NO_ERROR; + } }; -class SubscribeAttributeBooleanSensorConfigurationAlarmsEnabled : public SubscribeAttribute { +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + +/* + * Attribute SensorFault + */ +class ReadBooleanStateConfigurationSensorFault : public ReadAttribute { public: - SubscribeAttributeBooleanSensorConfigurationAlarmsEnabled() - : SubscribeAttribute("alarms-enabled") + ReadBooleanStateConfigurationSensorFault() + : ReadAttribute("sensor-fault") + { + } + + ~ReadBooleanStateConfigurationSensorFault() + { + } + + CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override + { + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::SensorFault::Id; + + ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + [cluster readAttributeSensorFaultWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"BooleanStateConfiguration.SensorFault response %@", [value description]); + if (error == nil) { + RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); + } else { + LogNSError("BooleanStateConfiguration SensorFault read Error", error); + RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); + } + SetCommandExitStatus(error); + }]; + return CHIP_NO_ERROR; + } +}; + +class SubscribeAttributeBooleanStateConfigurationSensorFault : public SubscribeAttribute { +public: + SubscribeAttributeBooleanStateConfigurationSensorFault() + : SubscribeAttribute("sensor-fault") { } - ~SubscribeAttributeBooleanSensorConfigurationAlarmsEnabled() + ~SubscribeAttributeBooleanStateConfigurationSensorFault() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AlarmsEnabled::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::SensorFault::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -73750,10 +74107,10 @@ class SubscribeAttributeBooleanSensorConfigurationAlarmsEnabled : public Subscri if (mAutoResubscribe.HasValue()) { params.resubscribeAutomatically = mAutoResubscribe.Value(); } - [cluster subscribeAttributeAlarmsEnabledWithParams:params + [cluster subscribeAttributeSensorFaultWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AlarmsEnabled response %@", [value description]); + NSLog(@"BooleanStateConfiguration.SensorFault response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -73772,32 +74129,32 @@ class SubscribeAttributeBooleanSensorConfigurationAlarmsEnabled : public Subscri /* * Attribute GeneratedCommandList */ -class ReadBooleanSensorConfigurationGeneratedCommandList : public ReadAttribute { +class ReadBooleanStateConfigurationGeneratedCommandList : public ReadAttribute { public: - ReadBooleanSensorConfigurationGeneratedCommandList() + ReadBooleanStateConfigurationGeneratedCommandList() : ReadAttribute("generated-command-list") { } - ~ReadBooleanSensorConfigurationGeneratedCommandList() + ~ReadBooleanStateConfigurationGeneratedCommandList() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::GeneratedCommandList::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::GeneratedCommandList::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; [cluster readAttributeGeneratedCommandListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.GeneratedCommandList response %@", [value description]); + NSLog(@"BooleanStateConfiguration.GeneratedCommandList response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration GeneratedCommandList read Error", error); + LogNSError("BooleanStateConfiguration GeneratedCommandList read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -73806,25 +74163,25 @@ class ReadBooleanSensorConfigurationGeneratedCommandList : public ReadAttribute } }; -class SubscribeAttributeBooleanSensorConfigurationGeneratedCommandList : public SubscribeAttribute { +class SubscribeAttributeBooleanStateConfigurationGeneratedCommandList : public SubscribeAttribute { public: - SubscribeAttributeBooleanSensorConfigurationGeneratedCommandList() + SubscribeAttributeBooleanStateConfigurationGeneratedCommandList() : SubscribeAttribute("generated-command-list") { } - ~SubscribeAttributeBooleanSensorConfigurationGeneratedCommandList() + ~SubscribeAttributeBooleanStateConfigurationGeneratedCommandList() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::GeneratedCommandList::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::GeneratedCommandList::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -73838,7 +74195,7 @@ class SubscribeAttributeBooleanSensorConfigurationGeneratedCommandList : public [cluster subscribeAttributeGeneratedCommandListWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.GeneratedCommandList response %@", [value description]); + NSLog(@"BooleanStateConfiguration.GeneratedCommandList response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -73857,32 +74214,32 @@ class SubscribeAttributeBooleanSensorConfigurationGeneratedCommandList : public /* * Attribute AcceptedCommandList */ -class ReadBooleanSensorConfigurationAcceptedCommandList : public ReadAttribute { +class ReadBooleanStateConfigurationAcceptedCommandList : public ReadAttribute { public: - ReadBooleanSensorConfigurationAcceptedCommandList() + ReadBooleanStateConfigurationAcceptedCommandList() : ReadAttribute("accepted-command-list") { } - ~ReadBooleanSensorConfigurationAcceptedCommandList() + ~ReadBooleanStateConfigurationAcceptedCommandList() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AcceptedCommandList::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AcceptedCommandList::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; [cluster readAttributeAcceptedCommandListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AcceptedCommandList response %@", [value description]); + NSLog(@"BooleanStateConfiguration.AcceptedCommandList response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration AcceptedCommandList read Error", error); + LogNSError("BooleanStateConfiguration AcceptedCommandList read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -73891,25 +74248,25 @@ class ReadBooleanSensorConfigurationAcceptedCommandList : public ReadAttribute { } }; -class SubscribeAttributeBooleanSensorConfigurationAcceptedCommandList : public SubscribeAttribute { +class SubscribeAttributeBooleanStateConfigurationAcceptedCommandList : public SubscribeAttribute { public: - SubscribeAttributeBooleanSensorConfigurationAcceptedCommandList() + SubscribeAttributeBooleanStateConfigurationAcceptedCommandList() : SubscribeAttribute("accepted-command-list") { } - ~SubscribeAttributeBooleanSensorConfigurationAcceptedCommandList() + ~SubscribeAttributeBooleanStateConfigurationAcceptedCommandList() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AcceptedCommandList::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AcceptedCommandList::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -73923,7 +74280,7 @@ class SubscribeAttributeBooleanSensorConfigurationAcceptedCommandList : public S [cluster subscribeAttributeAcceptedCommandListWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AcceptedCommandList response %@", [value description]); + NSLog(@"BooleanStateConfiguration.AcceptedCommandList response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -73942,32 +74299,32 @@ class SubscribeAttributeBooleanSensorConfigurationAcceptedCommandList : public S /* * Attribute EventList */ -class ReadBooleanSensorConfigurationEventList : public ReadAttribute { +class ReadBooleanStateConfigurationEventList : public ReadAttribute { public: - ReadBooleanSensorConfigurationEventList() + ReadBooleanStateConfigurationEventList() : ReadAttribute("event-list") { } - ~ReadBooleanSensorConfigurationEventList() + ~ReadBooleanStateConfigurationEventList() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::EventList::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::EventList::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; [cluster readAttributeEventListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.EventList response %@", [value description]); + NSLog(@"BooleanStateConfiguration.EventList response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration EventList read Error", error); + LogNSError("BooleanStateConfiguration EventList read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -73976,25 +74333,25 @@ class ReadBooleanSensorConfigurationEventList : public ReadAttribute { } }; -class SubscribeAttributeBooleanSensorConfigurationEventList : public SubscribeAttribute { +class SubscribeAttributeBooleanStateConfigurationEventList : public SubscribeAttribute { public: - SubscribeAttributeBooleanSensorConfigurationEventList() + SubscribeAttributeBooleanStateConfigurationEventList() : SubscribeAttribute("event-list") { } - ~SubscribeAttributeBooleanSensorConfigurationEventList() + ~SubscribeAttributeBooleanStateConfigurationEventList() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::EventList::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::EventList::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -74008,7 +74365,7 @@ class SubscribeAttributeBooleanSensorConfigurationEventList : public SubscribeAt [cluster subscribeAttributeEventListWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.EventList response %@", [value description]); + NSLog(@"BooleanStateConfiguration.EventList response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -74027,32 +74384,32 @@ class SubscribeAttributeBooleanSensorConfigurationEventList : public SubscribeAt /* * Attribute AttributeList */ -class ReadBooleanSensorConfigurationAttributeList : public ReadAttribute { +class ReadBooleanStateConfigurationAttributeList : public ReadAttribute { public: - ReadBooleanSensorConfigurationAttributeList() + ReadBooleanStateConfigurationAttributeList() : ReadAttribute("attribute-list") { } - ~ReadBooleanSensorConfigurationAttributeList() + ~ReadBooleanStateConfigurationAttributeList() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AttributeList::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AttributeList::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; [cluster readAttributeAttributeListWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AttributeList response %@", [value description]); + NSLog(@"BooleanStateConfiguration.AttributeList response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration AttributeList read Error", error); + LogNSError("BooleanStateConfiguration AttributeList read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -74061,25 +74418,25 @@ class ReadBooleanSensorConfigurationAttributeList : public ReadAttribute { } }; -class SubscribeAttributeBooleanSensorConfigurationAttributeList : public SubscribeAttribute { +class SubscribeAttributeBooleanStateConfigurationAttributeList : public SubscribeAttribute { public: - SubscribeAttributeBooleanSensorConfigurationAttributeList() + SubscribeAttributeBooleanStateConfigurationAttributeList() : SubscribeAttribute("attribute-list") { } - ~SubscribeAttributeBooleanSensorConfigurationAttributeList() + ~SubscribeAttributeBooleanStateConfigurationAttributeList() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::AttributeList::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::AttributeList::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -74093,7 +74450,7 @@ class SubscribeAttributeBooleanSensorConfigurationAttributeList : public Subscri [cluster subscribeAttributeAttributeListWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.AttributeList response %@", [value description]); + NSLog(@"BooleanStateConfiguration.AttributeList response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -74112,32 +74469,32 @@ class SubscribeAttributeBooleanSensorConfigurationAttributeList : public Subscri /* * Attribute FeatureMap */ -class ReadBooleanSensorConfigurationFeatureMap : public ReadAttribute { +class ReadBooleanStateConfigurationFeatureMap : public ReadAttribute { public: - ReadBooleanSensorConfigurationFeatureMap() + ReadBooleanStateConfigurationFeatureMap() : ReadAttribute("feature-map") { } - ~ReadBooleanSensorConfigurationFeatureMap() + ~ReadBooleanStateConfigurationFeatureMap() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::FeatureMap::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::FeatureMap::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; [cluster readAttributeFeatureMapWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.FeatureMap response %@", [value description]); + NSLog(@"BooleanStateConfiguration.FeatureMap response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration FeatureMap read Error", error); + LogNSError("BooleanStateConfiguration FeatureMap read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -74146,25 +74503,25 @@ class ReadBooleanSensorConfigurationFeatureMap : public ReadAttribute { } }; -class SubscribeAttributeBooleanSensorConfigurationFeatureMap : public SubscribeAttribute { +class SubscribeAttributeBooleanStateConfigurationFeatureMap : public SubscribeAttribute { public: - SubscribeAttributeBooleanSensorConfigurationFeatureMap() + SubscribeAttributeBooleanStateConfigurationFeatureMap() : SubscribeAttribute("feature-map") { } - ~SubscribeAttributeBooleanSensorConfigurationFeatureMap() + ~SubscribeAttributeBooleanStateConfigurationFeatureMap() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::FeatureMap::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::FeatureMap::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -74178,7 +74535,7 @@ class SubscribeAttributeBooleanSensorConfigurationFeatureMap : public SubscribeA [cluster subscribeAttributeFeatureMapWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.FeatureMap response %@", [value description]); + NSLog(@"BooleanStateConfiguration.FeatureMap response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -74197,32 +74554,32 @@ class SubscribeAttributeBooleanSensorConfigurationFeatureMap : public SubscribeA /* * Attribute ClusterRevision */ -class ReadBooleanSensorConfigurationClusterRevision : public ReadAttribute { +class ReadBooleanStateConfigurationClusterRevision : public ReadAttribute { public: - ReadBooleanSensorConfigurationClusterRevision() + ReadBooleanStateConfigurationClusterRevision() : ReadAttribute("cluster-revision") { } - ~ReadBooleanSensorConfigurationClusterRevision() + ~ReadBooleanStateConfigurationClusterRevision() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::ClusterRevision::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::ClusterRevision::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; [cluster readAttributeClusterRevisionWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.ClusterRevision response %@", [value description]); + NSLog(@"BooleanStateConfiguration.ClusterRevision response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("BooleanSensorConfiguration ClusterRevision read Error", error); + LogNSError("BooleanStateConfiguration ClusterRevision read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -74231,25 +74588,25 @@ class ReadBooleanSensorConfigurationClusterRevision : public ReadAttribute { } }; -class SubscribeAttributeBooleanSensorConfigurationClusterRevision : public SubscribeAttribute { +class SubscribeAttributeBooleanStateConfigurationClusterRevision : public SubscribeAttribute { public: - SubscribeAttributeBooleanSensorConfigurationClusterRevision() + SubscribeAttributeBooleanStateConfigurationClusterRevision() : SubscribeAttribute("cluster-revision") { } - ~SubscribeAttributeBooleanSensorConfigurationClusterRevision() + ~SubscribeAttributeBooleanStateConfigurationClusterRevision() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { - constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanSensorConfiguration::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanSensorConfiguration::Attributes::ClusterRevision::Id; + constexpr chip::ClusterId clusterId = chip::app::Clusters::BooleanStateConfiguration::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::BooleanStateConfiguration::Attributes::ClusterRevision::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterBooleanSensorConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; + __auto_type * cluster = [[MTRBaseClusterBooleanStateConfiguration alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; if (mKeepSubscriptions.HasValue()) { params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); @@ -74263,7 +74620,7 @@ class SubscribeAttributeBooleanSensorConfigurationClusterRevision : public Subsc [cluster subscribeAttributeClusterRevisionWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"BooleanSensorConfiguration.ClusterRevision response %@", [value description]); + NSLog(@"BooleanStateConfiguration.ClusterRevision response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -176201,62 +176558,80 @@ void registerClusterActivatedCarbonFilterMonitoring(Commands & commands) commands.RegisterCluster(clusterName, clusterCommands); #endif // MTR_ENABLE_PROVISIONAL } -void registerClusterBooleanSensorConfiguration(Commands & commands) +void registerClusterBooleanStateConfiguration(Commands & commands) { #if MTR_ENABLE_PROVISIONAL - using namespace chip::app::Clusters::BooleanSensorConfiguration; + using namespace chip::app::Clusters::BooleanStateConfiguration; - const char * clusterName = "BooleanSensorConfiguration"; + const char * clusterName = "BooleanStateConfiguration"; commands_list clusterCommands = { make_unique(Id), // #if MTR_ENABLE_PROVISIONAL - make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL make_unique(Id), // make_unique(Id), // make_unique(Id), // #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL make_unique(Id), // make_unique(Id), // @@ -180095,7 +180470,7 @@ void registerClusters(Commands & commands) registerClusterRvcOperationalState(commands); registerClusterHepaFilterMonitoring(commands); registerClusterActivatedCarbonFilterMonitoring(commands); - registerClusterBooleanSensorConfiguration(commands); + registerClusterBooleanStateConfiguration(commands); registerClusterValveConfigurationAndControl(commands); registerClusterElectricalEnergyMeasurement(commands); registerClusterDemandResponseLoadControl(commands);