@@ -126,13 +126,29 @@ package matter.controller.cluster.clusters
126
126
import java.util.logging.Level
127
127
import java.util.logging.Logger
128
128
import java.time.Duration
129
+ import kotlinx.coroutines.flow.Flow
130
+ import kotlinx.coroutines.flow.transform
129
131
import matter.controller.MatterController
130
132
import matter.controller.ReadRequest
131
133
import matter.controller.ReadData
132
134
import matter.controller.ReadFailure
133
135
import matter.controller.ReadResponse
134
136
import matter.controller.SubscribeRequest
135
137
import matter.controller.SubscriptionState
138
+ import matter.controller.ByteSubscriptionState
139
+ import matter.controller.ShortSubscriptionState
140
+ import matter.controller.IntSubscriptionState
141
+ import matter.controller.LongSubscriptionState
142
+ import matter.controller.FloatSubscriptionState
143
+ import matter.controller.DoubleSubscriptionState
144
+ import matter.controller.CharSubscriptionState
145
+ import matter.controller.BooleanSubscriptionState
146
+ import matter.controller.UByteSubscriptionState
147
+ import matter.controller.UShortSubscriptionState
148
+ import matter.controller.UIntSubscriptionState
149
+ import matter.controller.ULongSubscriptionState
150
+ import matter.controller.StringSubscriptionState
151
+ import matter.controller.ByteArraySubscriptionState
136
152
import matter.controller.WriteRequest
137
153
import matter.controller.WriteRequests
138
154
import matter.controller.WriteResponse
@@ -173,9 +189,20 @@ class {{cluster.name}}Cluster(private val controller: MatterController, private
173
189
{% - set encodable = attribute .definition | asEncodable (typeLookup ) -%}
174
190
{% - set interfaceName = attribute | javaAttributeCallbackName (typeLookup ) -%}
175
191
{% - if interfaceName not in already_handled_attribute %}
192
+ {% - set valueType = encode_value (cluster , encodable , 0) -%}
176
193
class {{interfaceName}}(
177
- val value: {{encode_value(cluster, encodable, 0) }}
194
+ val value: {{valueType }}
178
195
)
196
+
197
+ sealed class {{interfaceName}}SubscriptionState {
198
+ data class Success(
199
+ val value: {{valueType}}
200
+ ) : {{interfaceName}}SubscriptionState()
201
+
202
+ data class Error(val exception: Exception) : {{interfaceName}}SubscriptionState()
203
+
204
+ object SubscriptionEstablished : {{interfaceName}}SubscriptionState()
205
+ }
179
206
{% if already_handled_attribute .append (interfaceName ) -%}
180
207
{#- This block does nothing, it only exists to append to already_handled_attribute. -#}
181
208
{% - endif -%}
@@ -387,6 +414,63 @@ class {{cluster.name}}Cluster(private val controller: MatterController, private
387
414
}
388
415
}
389
416
{% endif %}
417
+ {% - if attribute .is_subscribable %}
418
+ {% - set encodable = attribute .definition | asEncodable (typeLookup ) %}
419
+ {% - set encodable_was_optional = encodable .is_optional or encodable .is_nullable %}
420
+ suspend fun subscribe{{ attribute.definition.name | upfirst }}Attribute(
421
+ minInterval: Int,
422
+ maxInterval: Int
423
+ ): Flow<{{interfaceName}}SubscriptionState> {
424
+ val ATTRIBUTE_ID: UInt = {{attribute.definition.code}}u
425
+ val attributePaths = listOf(
426
+ AttributePath(
427
+ endpointId = endpointId,
428
+ clusterId = CLUSTER_ID,
429
+ attributeId = ATTRIBUTE_ID
430
+ )
431
+ )
432
+
433
+ val subscribeRequest: SubscribeRequest = SubscribeRequest(
434
+ eventPaths = emptyList(),
435
+ attributePaths = attributePaths,
436
+ minInterval = Duration.ofSeconds(minInterval.toLong()),
437
+ maxInterval = Duration.ofSeconds(maxInterval.toLong())
438
+ )
439
+
440
+ return controller.subscribe(subscribeRequest).transform { subscriptionState ->
441
+ when (subscriptionState) {
442
+ is SubscriptionState.SubscriptionErrorNotification -> {
443
+ emit({{interfaceName}}SubscriptionState.Error(Exception("Subscription terminated with error code: ${subscriptionState.terminationCause}")))
444
+ }
445
+ is SubscriptionState.NodeStateUpdate -> {
446
+ val attributeData =
447
+ subscriptionState.updateState.successes.filterIsInstance<ReadData .Attribute >().firstOrNull {
448
+ it.path.attributeId == ATTRIBUTE_ID
449
+ }
450
+
451
+ requireNotNull(attributeData) {
452
+ "{{ attribute.definition.name | capitalize }} attribute not found in Node State update"
453
+ }
454
+
455
+ // Decode the TLV data into the appropriate type
456
+ val tlvReader = TlvReader(attributeData.data)
457
+ val decodedValue: {{encode_value(cluster, encodable, 0)}} = {{decode_tlv(cluster, attribute.definition | asEncodable(typeLookup), "AnonymousTag", 0)}}
458
+
459
+ {% if encodable_was_optional -%}
460
+ decodedValue?.let {
461
+ emit({{interfaceName}}SubscriptionState.Success(it))
462
+ }
463
+ {% else -%}
464
+ emit({{interfaceName}}SubscriptionState.Success(decodedValue))
465
+ {% - endif %}
466
+ }
467
+ SubscriptionState.SubscriptionEstablished -> {
468
+ emit({{interfaceName}}SubscriptionState.SubscriptionEstablished)
469
+ }
470
+ }
471
+ }
472
+ }
473
+ {% endif -%}
390
474
{% - endfor %}
391
475
companion object {
392
476
private val logger = Logger.getLogger({{cluster.name}}Cluster::class.java.name)
0 commit comments