-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use ProviderChangeListener directly to report attrbiute change #36756
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -88,6 +88,26 @@ std::optional<CHIP_ERROR> TryWriteViaAccessInterface(const ConcreteDataAttribute | |
|
||
} // namespace | ||
|
||
namespace detail { | ||
|
||
void DefaultProviderChangeListener::MarkDirty(const AttributePathParams & path) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add unit tests for this. |
||
{ | ||
ContextAttributesChangeListener change_listener(mProvider.CurrentContext()); | ||
if (path.mClusterId != kInvalidClusterId) | ||
{ | ||
emberAfAttributeChanged(path.mEndpointId, path.mClusterId, path.mAttributeId, &change_listener); | ||
} | ||
else | ||
{ | ||
// When the path has wildcard cluster Id, call the emberAfEndpointChanged to mark attributes on the given endpoint | ||
// as having changing, but do NOT increase/alter any cluster data versions, as this happens when a bridged endpoint is | ||
// added or removed from a bridge and the cluster data is not changed during the process. | ||
emberAfEndpointChanged(path.mEndpointId, &change_listener); | ||
} | ||
} | ||
|
||
} // namespace detail | ||
|
||
DataModel::ActionReturnStatus CodegenDataModelProvider::WriteAttribute(const DataModel::WriteAttributeRequest & request, | ||
AttributeValueDecoder & decoder) | ||
{ | ||
|
@@ -261,21 +281,5 @@ DataModel::ActionReturnStatus CodegenDataModelProvider::WriteAttribute(const Dat | |
return CHIP_NO_ERROR; | ||
} | ||
|
||
void CodegenDataModelProvider::Temporary_ReportAttributeChanged(const AttributePathParams & path) | ||
{ | ||
ContextAttributesChangeListener change_listener(CurrentContext()); | ||
if (path.mClusterId != kInvalidClusterId) | ||
{ | ||
emberAfAttributeChanged(path.mEndpointId, path.mClusterId, path.mAttributeId, &change_listener); | ||
} | ||
else | ||
{ | ||
// When the path has wildcard cluster Id, call the emberAfEndpointChanged to mark attributes on the given endpoint | ||
// as having changing, but do NOT increase/alter any cluster data versions, as this happens when a bridged endpoint is | ||
// added or removed from a bridge and the cluster data is not changed during the process. | ||
emberAfEndpointChanged(path.mEndpointId, &change_listener); | ||
} | ||
} | ||
|
||
} // namespace app | ||
} // namespace chip |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -97,6 +97,15 @@ class Provider : public ProviderMetadataTree | |
virtual std::optional<ActionReturnStatus> Invoke(const InvokeRequest & request, chip::TLV::TLVReader & input_arguments, | ||
CommandHandler * handler) = 0; | ||
|
||
/// Returns a reference to the ProviderChangeListener used for reporting attribute changes. | ||
/// | ||
/// This is used to notify listeners about changes in attributes managed by the provider. | ||
/// Listeners can be used to react to updates in the underlying data model. | ||
/// | ||
/// It is expected that implementations provide a valid reference, ensuring that | ||
/// attribute change reporting is functional throughout the lifecycle of the Provider. | ||
virtual ProviderChangeListener & GetAttributeChangeReporter() = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we hit naming again. A I would add to the comments that direct hookups to this should eventually be rare and to prefer to get passed in such change listeners in constructors for easier testing/mocking. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still don't understand what the actual long-term plan here is. Specifically:
ProviderChangeListener seems to be designed to be a per-InteractionModelContext singleton right now, but this is not how it's being used here... Also, how is ProviderChangeListener different from It feels like we are adding more and more complexity here without a clear plan for what the final (simple!) goal should be. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can define some design doc ... maybe we should start in releases. In my mind:
I am looking for a binding between
Thoughts? Should we create some dock/hackmd or chat separaely to actually define what is sane? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't tell whether the above bullets are mutually exclusive or "we should do both these things" (in the first set of two bullets). Doing a sync discussion about this sounds like it might be good, just to make sure we are not talking past each other.... But my first question is this: why should the DataVersion be owned by the provider, not the cluster implementation? Is that so we can use the same cluster implementation with different providers? And if the idea is that the provider owns the DataVersion, why do we have a separate interface defined for telling it "data version should update" instead of just having that be a method on the provider? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This probably warrants some design doc/discussion. Will see about creating one and discussing separately. In my mind:
|
||
|
||
private: | ||
InteractionModelContext mContext = { nullptr }; | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,14 @@ class TestOnlyAttributeValueDecoderAccessor | |
AttributeValueDecoder & mDecoder; | ||
}; | ||
|
||
class TestProviderChangeListener : public DataModel::ProviderChangeListener | ||
{ | ||
public: | ||
explicit TestProviderChangeListener() {} | ||
|
||
void MarkDirty(const AttributePathParams & path) override {} | ||
}; | ||
|
||
// strong defintion in TestCommandInteraction.cpp | ||
__attribute__((weak)) void DispatchSingleClusterCommand(const ConcreteCommandPath & aRequestCommandPath, | ||
chip::TLV::TLVReader & aReader, CommandHandler * apCommandObj) | ||
|
@@ -149,6 +157,12 @@ std::optional<ActionReturnStatus> TestImCustomDataModel::Invoke(const InvokeRequ | |
return std::make_optional<ActionReturnStatus>(CHIP_ERROR_NOT_IMPLEMENTED); | ||
} | ||
|
||
ProviderChangeListener & TestImCustomDataModel::GetAttributeChangeReporter() | ||
{ | ||
static TestProviderChangeListener changeListener; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why static? Since this is a test, could this thing be a property of the object itself? We could make it accumulate a std::vector of attributepathparams passed in, so we can validate their values. |
||
return changeListener; | ||
} | ||
|
||
DataModel::EndpointEntry TestImCustomDataModel::FirstEndpoint() | ||
{ | ||
return CodegenDataModelProviderInstance(nullptr /* delegate */)->FirstEndpoint(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets place this in its own header. I also believe that
detail::app::detail::DefaultProviderChangeListener
does not make it obvious on what it is. This is not any default but rather maybeEmberDirtyMarker
orEmberProviderChangeListener
orCodegenProviderChangeListener
Thinking of it maybe eventually as we stabilize the API we can figure out a better name than
ProviderChangeListener
as that name makes me think of "a listener that gets notified when a provider changes" which is not at all what it is. Do you have any suggestions?Something like
AttributeDirtyMarker
orDataChangeNotifier
or something like that. Obviously not for this PR, but this PR made it obvious to me that the naming is not great.