27
27
from ctypes import CFUNCTYPE , POINTER , c_size_t , c_uint8 , c_uint16 , c_uint32 , c_uint64 , c_void_p , cast , py_object
28
28
from dataclasses import dataclass , field
29
29
from enum import Enum , unique
30
- from typing import Any , Callable , Dict , List , Optional , Tuple , Union
30
+ from typing import Any , Callable , Dict , List , Optional , Set , Tuple , Union
31
31
32
32
import chip
33
33
import chip .exceptions
34
34
import chip .interaction_model
35
35
import chip .tlv
36
- import construct
36
+ import construct # type: ignore
37
37
from chip .interaction_model import PyWriteAttributeData
38
38
from chip .native import ErrorSDKPart , PyChipError
39
- from rich .pretty import pprint
39
+ from rich .pretty import pprint # type: ignore
40
40
41
41
from .ClusterObjects import Cluster , ClusterAttributeDescriptor , ClusterEvent
42
42
@@ -58,9 +58,9 @@ class EventPriority(Enum):
58
58
59
59
@dataclass (frozen = True )
60
60
class AttributePath :
61
- EndpointId : int = None
62
- ClusterId : int = None
63
- AttributeId : int = None
61
+ EndpointId : Optional [ int ] = None
62
+ ClusterId : Optional [ int ] = None
63
+ AttributeId : Optional [ int ] = None
64
64
65
65
@staticmethod
66
66
def from_cluster (EndpointId : int , Cluster : Cluster ) -> AttributePath :
@@ -80,12 +80,12 @@ def __str__(self) -> str:
80
80
81
81
@dataclass (frozen = True )
82
82
class DataVersionFilter :
83
- EndpointId : int = None
84
- ClusterId : int = None
85
- DataVersion : int = None
83
+ EndpointId : Optional [ int ] = None
84
+ ClusterId : Optional [ int ] = None
85
+ DataVersion : Optional [ int ] = None
86
86
87
87
@staticmethod
88
- def from_cluster (EndpointId : int , Cluster : Cluster , DataVersion : int = None ) -> AttributePath :
88
+ def from_cluster (EndpointId : int , Cluster : Cluster , DataVersion : int ) -> DataVersionFilter :
89
89
if Cluster is None :
90
90
raise ValueError ("Cluster cannot be None" )
91
91
return DataVersionFilter (EndpointId = EndpointId , ClusterId = Cluster .id , DataVersion = DataVersion )
@@ -99,70 +99,67 @@ class TypedAttributePath:
99
99
''' Encapsulates an attribute path that has strongly typed references to cluster and attribute
100
100
cluster object types. These types serve as keys into the attribute cache.
101
101
'''
102
- ClusterType : Cluster = None
103
- AttributeType : ClusterAttributeDescriptor = None
104
- AttributeName : str = None
105
- Path : AttributePath = None
106
-
107
- def __init__ (self , ClusterType : Cluster = None , AttributeType : ClusterAttributeDescriptor = None ,
108
- Path : AttributePath = None ):
109
- ''' Only one of either ClusterType and AttributeType OR Path may be provided.
110
- '''
111
-
112
- #
113
- # First, let's populate ClusterType and AttributeType. If it's already provided,
114
- # we can continue onwards to deriving the label. Otherwise, we'll need to
115
- # walk the attribute index to find the right type information.
116
- #
117
- if (ClusterType is not None and AttributeType is not None ):
118
- self .ClusterType = ClusterType
119
- self .AttributeType = AttributeType
120
- else :
121
- if (Path is None ):
122
- raise ValueError ("Path should have a valid value" )
123
-
102
+ ClusterType : Optional [Cluster ] = None
103
+ AttributeType : Optional [ClusterAttributeDescriptor ] = None
104
+ AttributeName : Optional [str ] = None
105
+ Path : Optional [AttributePath ] = None
106
+ ClusterId : Optional [int ] = None
107
+ AttributeId : Optional [int ] = None
108
+
109
+ def __post_init__ (self ):
110
+ '''Only one of either ClusterType and AttributeType OR Path may be provided.'''
111
+
112
+ if (self .ClusterType is not None and self .AttributeType is not None ) and self .Path is not None :
113
+ raise ValueError ("Only one of either ClusterType and AttributeType OR Path may be provided." )
114
+ if (self .ClusterType is None or self .AttributeType is None ) and self .Path is None :
115
+ raise ValueError ("Either ClusterType and AttributeType OR Path must be provided." )
116
+
117
+ # if ClusterType and AttributeType were provided we can continue onwards to deriving the label.
118
+ # Otherwise, we'll need to walk the attribute index to find the right type information.
119
+
120
+ # If Path is provided, derive ClusterType and AttributeType from it
121
+ if self .Path is not None :
124
122
for cluster , attribute in _AttributeIndex :
125
123
attributeType = _AttributeIndex [(cluster , attribute )][0 ]
126
124
clusterType = _AttributeIndex [(cluster , attribute )][1 ]
127
125
128
- if ( clusterType .id == Path .ClusterId and attributeType .attribute_id == Path .AttributeId ) :
126
+ if clusterType .id == self . Path .ClusterId and attributeType .attribute_id == self . Path .AttributeId :
129
127
self .ClusterType = clusterType
130
128
self .AttributeType = attributeType
131
129
break
132
130
133
- if ( self .ClusterType is None or self .AttributeType is None ) :
134
- raise KeyError (f"No Schema found for Attribute { Path } " )
131
+ if self .ClusterType is None or self .AttributeType is None :
132
+ raise KeyError (f"No Schema found for Attribute { self . Path } " )
135
133
136
134
# Next, let's figure out the label.
137
135
for c_field in self .ClusterType .descriptor .Fields :
138
- if ( c_field .Tag != self .AttributeType .attribute_id ) :
136
+ if c_field .Tag != self .AttributeType .attribute_id :
139
137
continue
140
138
141
139
self .AttributeName = c_field .Label
142
140
143
- if ( self .AttributeName is None ) :
144
- raise KeyError (f"Unable to resolve name for Attribute { Path } " )
141
+ if self .AttributeName is None :
142
+ raise KeyError (f"Unable to resolve name for Attribute { self . Path } " )
145
143
146
- self .Path = Path
147
144
self .ClusterId = self .ClusterType .id
148
145
self .AttributeId = self .AttributeType .attribute_id
149
146
150
147
151
148
@dataclass (frozen = True )
152
149
class EventPath :
153
- EndpointId : int = None
154
- ClusterId : int = None
155
- EventId : int = None
156
- Urgent : int = None
150
+ EndpointId : Optional [ int ] = None
151
+ ClusterId : Optional [ int ] = None
152
+ EventId : Optional [ int ] = None
153
+ Urgent : Optional [ int ] = None
157
154
158
155
@staticmethod
159
- def from_cluster (EndpointId : int , Cluster : Cluster , EventId : int = None , Urgent : int = None ) -> "EventPath" :
156
+ def from_cluster (EndpointId : int , Cluster : Cluster , EventId : Optional [ int ] = None , Urgent : Optional [ int ] = None ) -> "EventPath" :
160
157
if Cluster is None :
161
158
raise ValueError ("Cluster cannot be None" )
162
159
return EventPath (EndpointId = EndpointId , ClusterId = Cluster .id , EventId = EventId , Urgent = Urgent )
163
160
164
161
@staticmethod
165
- def from_event (EndpointId : int , Event : ClusterEvent , Urgent : int = None ) -> "EventPath" :
162
+ def from_event (EndpointId : int , Event : ClusterEvent , Urgent : Optional [ int ] = None ) -> "EventPath" :
166
163
if Event is None :
167
164
raise ValueError ("Event cannot be None" )
168
165
return EventPath (EndpointId = EndpointId , ClusterId = Event .cluster_id , EventId = Event .event_id , Urgent = Urgent )
@@ -173,23 +170,13 @@ def __str__(self) -> str:
173
170
174
171
@dataclass
175
172
class EventHeader :
176
- EndpointId : int = None
177
- ClusterId : int = None
178
- EventId : int = None
179
- EventNumber : int = None
180
- Priority : EventPriority = None
181
- Timestamp : int = None
182
- TimestampType : EventTimestampType = None
183
-
184
- def __init__ (self , EndpointId : int = None , ClusterId : int = None ,
185
- EventId : int = None , EventNumber = None , Priority = None , Timestamp = None , TimestampType = None ):
186
- self .EndpointId = EndpointId
187
- self .ClusterId = ClusterId
188
- self .EventId = EventId
189
- self .EventNumber = EventNumber
190
- self .Priority = Priority
191
- self .Timestamp = Timestamp
192
- self .TimestampType = TimestampType
173
+ EndpointId : Optional [int ] = None
174
+ ClusterId : Optional [int ] = None
175
+ EventId : Optional [int ] = None
176
+ EventNumber : Optional [int ] = None
177
+ Priority : Optional [EventPriority ] = None
178
+ Timestamp : Optional [int ] = None
179
+ TimestampType : Optional [EventTimestampType ] = None
193
180
194
181
def __str__ (self ) -> str :
195
182
return (f"{ self .EndpointId } /{ self .ClusterId } /{ self .EventId } /"
@@ -247,7 +234,7 @@ class ValueDecodeFailure:
247
234
'''
248
235
249
236
TLVValue : Any = None
250
- Reason : Exception = None
237
+ Reason : Optional [ Exception ] = None
251
238
252
239
253
240
@dataclass
@@ -431,15 +418,16 @@ def handle_attribute_view(endpointId, clusterId, attributeId, attributeType):
431
418
432
419
class SubscriptionTransaction :
433
420
def __init__ (self , transaction : AsyncReadTransaction , subscriptionId , devCtrl ):
434
- self ._onResubscriptionAttemptedCb = DefaultResubscriptionAttemptedCallback
435
- self ._onAttributeChangeCb = DefaultAttributeChangeCallback
436
- self ._onEventChangeCb = DefaultEventChangeCallback
437
- self ._onErrorCb = DefaultErrorCallback
421
+ self ._onResubscriptionAttemptedCb : Callable [[SubscriptionTransaction ,
422
+ int , int ], None ] = DefaultResubscriptionAttemptedCallback
423
+ self ._onAttributeChangeCb : Callable [[TypedAttributePath , SubscriptionTransaction ], None ] = DefaultAttributeChangeCallback
424
+ self ._onEventChangeCb : Callable [[EventReadResult , SubscriptionTransaction ], None ] = DefaultEventChangeCallback
425
+ self ._onErrorCb : Callable [[int , SubscriptionTransaction ], None ] = DefaultErrorCallback
438
426
self ._readTransaction = transaction
439
427
self ._subscriptionId = subscriptionId
440
428
self ._devCtrl = devCtrl
441
429
self ._isDone = False
442
- self ._onResubscriptionSucceededCb = None
430
+ self ._onResubscriptionSucceededCb : Optional [ Callable [[ SubscriptionTransaction ], None ]] = None
443
431
self ._onResubscriptionSucceededCb_isAsync = False
444
432
self ._onResubscriptionAttemptedCb_isAsync = False
445
433
@@ -647,10 +635,10 @@ def __init__(self, future: Future, eventLoop, devCtrl, returnClusterObject: bool
647
635
self ._event_loop = eventLoop
648
636
self ._future = future
649
637
self ._subscription_handler = None
650
- self ._events = []
638
+ self ._events : List [ EventReadResult ] = []
651
639
self ._devCtrl = devCtrl
652
640
self ._cache = AttributeCache (returnClusterObject = returnClusterObject )
653
- self ._changedPathSet = set ()
641
+ self ._changedPathSet : Set [ AttributePath ] = set ()
654
642
self ._pReadClient = None
655
643
self ._pReadCallback = None
656
644
self ._resultError : Optional [PyChipError ] = None
@@ -809,7 +797,7 @@ class AsyncWriteTransaction:
809
797
def __init__ (self , future : Future , eventLoop ):
810
798
self ._event_loop = eventLoop
811
799
self ._future = future
812
- self ._resultData = []
800
+ self ._resultData : List [ AttributeWriteResult ] = []
813
801
self ._resultError : Optional [PyChipError ] = None
814
802
815
803
def handleResponse (self , path : AttributePath , status : int ):
@@ -1014,9 +1002,9 @@ def WriteGroupAttributes(groupId: int, devCtrl: c_void_p, attributes: List[Attri
1014
1002
1015
1003
1016
1004
def Read (future : Future , eventLoop , device , devCtrl ,
1017
- attributes : List [AttributePath ] = None , dataVersionFilters : List [DataVersionFilter ] = None ,
1018
- events : List [EventPath ] = None , eventNumberFilter : Optional [int ] = None , returnClusterObject : bool = True ,
1019
- subscriptionParameters : SubscriptionParameters = None ,
1005
+ attributes : Optional [ List [AttributePath ]] = None , dataVersionFilters : Optional [ List [DataVersionFilter ] ] = None ,
1006
+ events : Optional [ List [EventPath ] ] = None , eventNumberFilter : Optional [int ] = None , returnClusterObject : bool = True ,
1007
+ subscriptionParameters : Optional [ SubscriptionParameters ] = None ,
1020
1008
fabricFiltered : bool = True , keepSubscriptions : bool = False , autoResubscribe : bool = True ) -> PyChipError :
1021
1009
if (not attributes ) and dataVersionFilters :
1022
1010
raise ValueError (
@@ -1132,9 +1120,9 @@ def Read(future: Future, eventLoop, device, devCtrl,
1132
1120
1133
1121
1134
1122
def ReadAttributes (future : Future , eventLoop , device , devCtrl ,
1135
- attributes : List [AttributePath ], dataVersionFilters : List [DataVersionFilter ] = None ,
1123
+ attributes : List [AttributePath ], dataVersionFilters : Optional [ List [DataVersionFilter ] ] = None ,
1136
1124
returnClusterObject : bool = True ,
1137
- subscriptionParameters : SubscriptionParameters = None , fabricFiltered : bool = True ) -> int :
1125
+ subscriptionParameters : Optional [ SubscriptionParameters ] = None , fabricFiltered : bool = True ) -> int :
1138
1126
return Read (future = future , eventLoop = eventLoop , device = device ,
1139
1127
devCtrl = devCtrl , attributes = attributes , dataVersionFilters = dataVersionFilters ,
1140
1128
events = None , returnClusterObject = returnClusterObject ,
@@ -1143,7 +1131,7 @@ def ReadAttributes(future: Future, eventLoop, device, devCtrl,
1143
1131
1144
1132
def ReadEvents (future : Future , eventLoop , device , devCtrl ,
1145
1133
events : List [EventPath ], eventNumberFilter = None , returnClusterObject : bool = True ,
1146
- subscriptionParameters : SubscriptionParameters = None , fabricFiltered : bool = True ) -> int :
1134
+ subscriptionParameters : Optional [ SubscriptionParameters ] = None , fabricFiltered : bool = True ) -> int :
1147
1135
return Read (future = future , eventLoop = eventLoop , device = device , devCtrl = devCtrl , attributes = None ,
1148
1136
dataVersionFilters = None , events = events , eventNumberFilter = eventNumberFilter ,
1149
1137
returnClusterObject = returnClusterObject ,
0 commit comments