Line data Source code
1 : /*
2 : * Copyright (c) 2026 Project CHIP Authors
3 : *
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 : #pragma once
19 :
20 : #include <app/ConcreteAttributePath.h>
21 :
22 : namespace chip::app::DataModel {
23 :
24 : /// Describes the level of an attribute change. The existence of this is to
25 : /// allow listeners to cater to two types of consumers:
26 : ///
27 : /// 1. Applications generally care about ALL changes to a value, since they
28 : /// may actuate hardware.
29 : ///
30 : /// 2. Matter Interaction model identifies things that are reported (i.e.
31 : /// generate traffic on the network and is visible to subscribers) and
32 : /// quiet changes (i.e. not reported).
33 : ///
34 : /// Examples of quiet changes are things that fluctuate (like a voltage
35 : /// measurement) where we only report "large changes" or things that
36 : /// continuously change (e.g. a current time would change, or a network
37 : /// packet count would increase as soon as a network packet is sent, and
38 : /// a network packet would be sent reporting the packet count)
39 : ///
40 : /// As such we will have constants that say:
41 : /// - kReportable: important/large change, reported to subscribers by Matter IM
42 : /// - kQuiet: value changed, would be visible on a `ReadAttribute` however it
43 : /// is not reported to subscribers.
44 : ///
45 : enum class AttributeChangeType
46 : {
47 : kReportable, // Change should be reported to subscribers
48 : kQuiet // Change is minor or configured not to be reported
49 : };
50 :
51 : /// Help listeners for endpoint changes to make a quick decision about
52 : /// what happened to an endpoint. This is because this is often cheaper
53 : /// to have at call time compared to querying a DataModel::Provider for example
54 : enum class EndpointChangeType
55 : {
56 : kAdded,
57 : kRemoved,
58 : };
59 :
60 : /// Interface for components wishing to be notified of attribute changes.
61 : ///
62 : /// Implement this interface to receive callbacks when attributes are modified
63 : /// within a DataModel::Provider. Listeners are registered with a specific
64 : /// DataModel::Provider instance.
65 : ///
66 : /// Notifications are:
67 : /// - Called *after* the attribute state has been updated in the provider.
68 : /// - Triggered for all attribute changes, regardless of whether they are
69 : /// IM-reportable (i.e., includes kQuiet changes).
70 : /// - Primarily used by the application layer to synchronize external state
71 : /// (e.g., hardware) with the new attribute value.
72 : /// - Synchronous: Called inline during the attribute update process.
73 : /// Implementations should be wary of re-entrancy or recursive calls if
74 : /// they modify cluster state within the callback.
75 : /// * you may also choose to defer cluster modifications to a separate
76 : /// scheduled task. That would not cause recursive calls, however
77 : /// not entering loops has to still be checked for.
78 : /// - Fire-and-forget: There is no mechanism to report failure back to the
79 : /// caller. If an action taken in the callback fails (e.g., hardware
80 : /// actuation), the listener is responsible for any corrective measures,
81 : /// such as reverting the attribute state in the DataModel::Provider.
82 : class AttributeChangeListener
83 : {
84 : public:
85 1254 : virtual ~AttributeChangeListener() = default;
86 :
87 : /// Called after an attribute's value has changed.
88 0 : virtual void OnAttributeChanged(const ConcreteAttributePath & path, AttributeChangeType type) {}
89 :
90 : /// Called when an endpoint's structure or composition changes
91 : /// (e.g., clusters added/removed, or for bridged device changes).
92 0 : virtual void OnEndpointChanged(EndpointId endpointId, EndpointChangeType type) {}
93 :
94 7645 : AttributeChangeListener * GetNextAttributeChangeListener() const { return mNextAttributeChange; }
95 1827 : void SetNextAttributeChangeListener(AttributeChangeListener * next) { mNextAttributeChange = next; }
96 :
97 : private:
98 : /// NOTE: single linked list to minimize resource overhead.
99 : ///
100 : /// This prioritizes low flash/ram overhead over extra functionality or safety (i.e. we cannot
101 : /// have a single listener registered to multiple providers, there is no specific loop
102 : /// detection or prevention).
103 : AttributeChangeListener * mNextAttributeChange = nullptr;
104 : };
105 :
106 : } // namespace chip::app::DataModel
|