CHIP
Matter
Firmware
Engineer
2022/05/14
CHIP git hash code 67b4746ad8
In this example, you would be able to control the locker by python controller if everything goes well. You may also see this kind of message in the device log:
00> <info > [ZCL] On/Off set value: 1 1
00> <info > [ZCL] Toggle on/off from 0 to 1
As you can image, if you build up this controller and install it to your phone, you could then control your front door locker by your phone. However, you probably also want to know when your door locker is unlocked or locked(at least I want to know…).
And the document in this example doesn't show you how to do make the locker device reports the status to the controller(your phone).
Therefore, if you are not familiar with ZCL just like me. Here are some steps to show you how I set up report function and I will have a brief walk through in the code.
The first thing we should know about the report is the zap file. This is the output file of the ZAP. In short, this program is to config clusters on both client and server side.
Boil down, if you look at the zap file, you will know that this is a readable json format file. Here is a snippet of the lock-app zap file(under examples/lock-app/lock-common):
{
"name": "On/Off",
"code": 6,
"mfgCode": null,
"define": "ON_OFF_CLUSTER",
"side": "server",
"enabled": 1,
"commands": [],
"attributes": [
{
"name": "OnOff",
"code": 0,
"mfgCode": null,
"side": "server",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0x00",
"reportable": 1,
"minInterval": 0,
"maxInterval": 65344,
"reportableChange": 0
},
...
]
},
As you can see, it defines a cluster called "On/Off" on server side. What we need to check here is the "reportable." Just make sure it is 1.
Also, you could learn more about the report attribute in the ZCL specification section 2.5.
Server is the thunderboard sense 2, client is python controller
You don't really have to do anything, just recompile and flash the image to the device.
There is a command called "zclconfig." We will use this command to set up the report interval.
chip-device-ctrl > zclconfigure OnOff OnOff 30 1 10 20 1
The 10 20
means min-max interval in SECOND.
Again, if everything goes well, you will see this kind of log on the controller side(if you open the log)
1632434820677] [2137:31085] CHIP: [DMG] ReportData =
[1632434820677] [2137:31085] CHIP: [DMG] {
[1632434820677] [2137:31085] CHIP: [DMG] SubscriptionId = 0x2782b66dc1448111,
[1632434820677] [2137:31085] CHIP: [DMG] AttributeDataList =
[1632434820677] [2137:31085] CHIP: [DMG] [
[1632434820677] [2137:31085] CHIP: [DMG] AttributeDataElement =
[1632434820677] [2137:31085] CHIP: [DMG] {
[1632434820677] [2137:31085] CHIP: [DMG] AttributePath =
[1632434820677] [2137:31085] CHIP: [DMG] {
[1632434820677] [2137:31085] CHIP: [DMG] NodeId = 0x1e,
[1632434820677] [2137:31085] CHIP: [DMG] EndpointId = 0x1,
[1632434820677] [2137:31085] CHIP: [DMG] ClusterId = 0x6,
[1632434820677] [2137:31085] CHIP: [DMG] FieldTag = 0x0,
[1632434820677] [2137:31085] CHIP: [DMG] }
[1632434820677] [2137:31085] CHIP: [DMG]
[1632434820677] [2137:31085] CHIP: [DMG] Data = true,
[1632434820677] [2137:31085] CHIP: [DMG] DataElementVersion = 0x0,
[1632434820677] [2137:31085] CHIP: [DMG] },
[1632434820677] [2137:31085] CHIP: [DMG]
[1632434820677] [2137:31085] CHIP: [DMG] ],
[1632434820677] [2137:31085] CHIP: [DMG]
[1632434820677] [2137:31085] CHIP: [DMG] }
[1632434820678] [2137:31085] CHIP: [ZCL] ReadAttributesResponse:
[1632434820678] [2137:31085] CHIP: [ZCL] ClusterId: 0x0000_0006
In python controller, if you follow the calling stack of command zclconfig, you will find out the command type of this command is Protocols::InteractionModel::MsgType::SubscribeRequest. Thus, on server side, we have to find out which component register for this command type.
In InteractionModelEngine::Init, you can find this line of code
ReturnErrorOnFailure(mpExchangeMgr->RegisterUnsolicitedMessageHandlerForProtocol(Protocols::InteractionModel::Id, this));
It is showing you that this class(InteractionModelEngine) register for all commands with protocol ID "InteractionModel". And Protocols::InteractionModel::MsgType::SubscribeRequest is under the "InteractionModel" ID. So the handler of this command is InteractionModelEngine.
This is the function we are going to start with. From this function, you can easily follow the calling stack:
In Engine::ScheduleRun, it schedules a work to the CHIP stack thread, and the work is
Engine::Run(System::Layer * aSystemLayer, void * apAppState)
In this function, it simply calls
Engine::Run()
There are three different type of system implements. I use the system/SystemLayerImplLwIP.cpp as example. In this file, you can find a function:
LayerImplLwIP::ScheduleWork(TimerCompleteCallback onComplete, void * appState).
It basically creates a timer, and the callback of this timer will call TimerCompleteCallback. And TimerCompleteCallback in our case is Engine::Run(System::Layer * aSystemLayer, void * apAppState)
Finally, you can find this block of code in this function:
while ((mNumReportsInFlight < CHIP_IM_MAX_REPORTS_IN_FLIGHT) && (numReadHandled < CHIP_IM_MAX_NUM_READ_HANDLER))
{
if (readHandler->IsReportable())
{
CHIP_ERROR err = BuildAndSendSingleReportData(readHandler);
if (err != CHIP_NO_ERROR)
{
return;
}
}
numReadHandled++;
mCurReadHandlerIdx = (mCurReadHandlerIdx + 1) % CHIP_IM_MAX_NUM_READ_HANDLER;
readHandler = imEngine->mReadHandlers + mCurReadHandlerIdx;
}
This is where the device will build and send out the report.
This is how device sends out the report, but you may have a problem which is "how the controller gets this report." I will have another note about this later.