Skip to content

Commit 438dfad

Browse files
committed
Add custom Node Descriptor response handling
With next firmware version and deCONZ v2.12.2-beta, Node Descriptor requests are forwarded to the application. The handler allows to customize the response for specific devices.
1 parent d1fbe7b commit 438dfad

File tree

5 files changed

+162
-0
lines changed

5 files changed

+162
-0
lines changed

de_web_plugin.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,12 @@ void DeRestPluginPrivate::apsdeDataIndication(const deCONZ::ApsDataIndication &i
11931193
{
11941194
switch (ind.clusterId())
11951195
{
1196+
case ZDP_NODE_DESCRIPTOR_CLID:
1197+
{
1198+
ZDP_HandleNodeDescriptorRequest(ind, apsCtrl);
1199+
}
1200+
break;
1201+
11961202
case ZDP_NODE_DESCRIPTOR_RSP_CLID:
11971203
{
11981204
// Safeguard to issue a 2nd active endpoint request in case the first one got MIA

utils/utils.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
*/
1010

1111
#include <deconz/aps.h>
12+
#include <deconz/aps_controller.h>
1213
#include <deconz/dbg_trace.h>
14+
#include <deconz/node.h>
1315
#include "utils.h"
1416
#include "resource.h"
1517

@@ -239,3 +241,25 @@ bool isSameAddress(const deCONZ::Address &a, const deCONZ::Address &b)
239241

240242
return true;
241243
}
244+
245+
const deCONZ::Node *getCoreNode(quint64 extAddress, deCONZ::ApsController *apsCtrl)
246+
{
247+
DBG_Assert(apsCtrl);
248+
249+
if (apsCtrl && extAddress != 0)
250+
{
251+
int i = 0;
252+
const deCONZ::Node *node = nullptr;
253+
254+
while (apsCtrl->getNode(i, &node) == 0)
255+
{
256+
if (node->address().ext() == extAddress)
257+
{
258+
return node;
259+
}
260+
i++;
261+
}
262+
}
263+
264+
return nullptr;
265+
}

utils/utils.h

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
namespace deCONZ {
2020
class Address;
21+
class ApsController;
22+
class Node;
2123
}
2224

2325
struct KeyMap
@@ -82,4 +84,6 @@ decltype(auto) matchKeyValue(const K &key, const Cont &cont)
8284
return ret;
8385
}
8486

87+
const deCONZ::Node *getCoreNode(quint64 extAddress, deCONZ::ApsController *apsCtrl);
88+
8589
#endif // UTILS_H

zdp/zdp_handlers.cpp

+121
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "de_web_plugin.h"
1212
#include "de_web_plugin_private.h"
13+
#include "utils/utils.h"
1314
#include "zdp_handlers.h"
1415

1516
/*! Handle the case that a node (re)joins the network.
@@ -250,6 +251,126 @@ void DeRestPluginPrivate::handleDeviceAnnceIndication(const deCONZ::ApsDataIndic
250251
}
251252
}
252253

254+
struct MapMfCode
255+
{
256+
quint64 macPrefix;
257+
quint16 mfcode;
258+
/* Bits 9-15. These bits indicate the revision of the ZigBee Pro Core specification that the running stack is implemented to. Prior
259+
to revision 21 of the specification these bits were reserved and thus set to 0. A stack that is compliant to revision 22
260+
would set these bits to 22 (0010110b). A stack shall indicate the revision of the specification it is compliant to by
261+
setting these bits.
262+
263+
0x0000 Reserved prior Rev. 21
264+
0x2A00 (21 << 9) Rev. 21
265+
0x2C00 (22 << 9) Rev. 22
266+
*/
267+
quint16 serverMask;
268+
};
269+
270+
static const std::array<MapMfCode, 3> mapMfCode = {
271+
{
272+
{ 0x04cf8c0000000000ULL, 0x115F, 0x0040}, // Xiaomi
273+
{ 0x54ef440000000000ULL, 0x115F, 0x0040} // Xiaomi
274+
}
275+
};
276+
277+
/*! Sends a Node Descriptor response.
278+
279+
Sends modified Manufacturer Code and Server Mask for some devices.
280+
281+
\param ind - a ZDP NodeDescriptor_req
282+
\param apsCtrl - APS controller instance
283+
*/
284+
void ZDP_HandleNodeDescriptorRequest(const deCONZ::ApsDataIndication &ind, deCONZ::ApsController *apsCtrl)
285+
{
286+
if (!apsCtrl)
287+
{
288+
return;
289+
}
290+
291+
const deCONZ::Node *self = getCoreNode(apsCtrl->getParameter(deCONZ::ParamMacAddress), apsCtrl);
292+
293+
if (!self)
294+
{
295+
return;
296+
}
297+
298+
quint8 seq;
299+
quint16 nwkAddr;
300+
301+
{
302+
QDataStream stream(ind.asdu());
303+
stream.setByteOrder(QDataStream::LittleEndian);
304+
305+
stream >> seq;
306+
stream >> nwkAddr;
307+
308+
if (stream.status() != QDataStream::Ok)
309+
{
310+
return;
311+
}
312+
}
313+
314+
if (nwkAddr != self->address().nwk())
315+
{
316+
return;
317+
}
318+
319+
quint16 mfCode = VENDOR_DDEL;
320+
quint16 serverMask = 0x0040; // compatible with stack revisions below version 21
321+
QByteArray ndRaw;
322+
323+
if (!self->nodeDescriptor().isNull())
324+
{
325+
ndRaw = self->nodeDescriptor().toByteArray();
326+
serverMask = static_cast<quint16>(self->nodeDescriptor().serverMask()) & 0xFFFF;
327+
}
328+
else // fallback if not known
329+
{
330+
ndRaw = QByteArray("\x10\x40\x0f\x35\x11\x47\x2b\x00\x40\x00\x2b\x00\x00", 13);
331+
}
332+
333+
auto i = std::find_if(mapMfCode.cbegin(), mapMfCode.cend(), [&ind](const auto &entry) {
334+
return (ind.srcAddress().ext() & entry.macPrefix) == entry.macPrefix;
335+
});
336+
337+
if (i != mapMfCode.cend())
338+
{
339+
mfCode = i->mfcode;
340+
serverMask = i->serverMask;
341+
}
342+
343+
{ // change manufacturer code and server mask if needed
344+
QDataStream stream(&ndRaw, QIODevice::WriteOnly);
345+
stream.setByteOrder(QDataStream::LittleEndian);
346+
347+
stream.device()->seek(3);
348+
stream << mfCode;
349+
stream.device()->seek(8);
350+
stream << serverMask;
351+
}
352+
353+
deCONZ::ApsDataRequest req;
354+
355+
req.setProfileId(ZDP_PROFILE_ID);
356+
req.setSrcEndpoint(ZDO_ENDPOINT);
357+
req.setDstEndpoint(ZDO_ENDPOINT);
358+
req.setClusterId(ZDP_NODE_DESCRIPTOR_RSP_CLID);
359+
req.setDstAddressMode(deCONZ::ApsNwkAddress);
360+
req.setTxOptions(deCONZ::ApsTxAcknowledgedTransmission);
361+
req.dstAddress() = ind.srcAddress();
362+
363+
QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
364+
stream.setByteOrder(QDataStream::LittleEndian);
365+
366+
stream << seq;
367+
stream << quint8(ZDP_SUCCESS);
368+
stream << nwkAddr;
369+
stream.writeRawData(ndRaw.constData(), ndRaw.size());
370+
371+
if (apsCtrl->apsdeDataRequest(req) == deCONZ::Success) { }
372+
}
373+
253374
/*! Handle node descriptor response.
254375
\param ind a ZDP NodeDescriptor_rsp
255376
*/

zdp/zdp_handlers.h

+7
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,11 @@
1212
#define ZDP_HANDLERS_H
1313

1414

15+
namespace deCONZ {
16+
class ApsController;
17+
class ApsDataIndication;
18+
}
19+
20+
void ZDP_HandleNodeDescriptorRequest(const deCONZ::ApsDataIndication &ind, deCONZ::ApsController *apsCtrl);
21+
1522
#endif // ZDP_HANDLERS_H

0 commit comments

Comments
 (0)