Improve startup procedure and node creation mechanism

This commit is contained in:
Simon Stürz 2019-05-14 21:27:07 +02:00
parent 0abeaa197b
commit 2922a87449
10 changed files with 67156 additions and 50 deletions

11
README.md Normal file
View File

@ -0,0 +1,11 @@
# nymea-zigbee
This repository contains the nymea-zigbee library and tools.
# Supported hardware
## NXP
* JN5168 (SoM)
* JN5169 (USB Stick)

File diff suppressed because one or more lines are too long

View File

@ -232,6 +232,7 @@ void ZigbeeInterface::disable()
delete m_serialPort;
m_serialPort = nullptr;
setAvailable(false);
qCDebug(dcZigbeeInterface()) << "Interface disabled";
}

View File

@ -261,7 +261,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeController::commandNodeDescriptorRequest(quint
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeNodeDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeNodeDescriptorRsponse);
request.setDescription("Node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress));
request.setTimoutIntervall(5000);
request.setTimoutIntervall(10000);
return sendRequest(request);
}
@ -275,7 +275,7 @@ ZigbeeInterfaceReply *ZigbeeBridgeController::commandSimpleDescriptorRequest(qui
ZigbeeInterfaceRequest request(ZigbeeInterfaceMessage(Zigbee::MessageTypeSimpleDescriptorRequest, data));
request.setExpectedAdditionalMessageType(Zigbee::MessageTypeSimpleDescriptorResponse);
request.setDescription("Simple node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress) + "endpoint " + QString::number(endpoint));
request.setDescription("Simple node descriptor request for " + ZigbeeUtils::convertUint16ToHexString(shortAddress) + " endpoint " + QString::number(endpoint));
request.setTimoutIntervall(5000);
return sendRequest(request);
@ -329,16 +329,24 @@ void ZigbeeBridgeController::onMessageReceived(const ZigbeeInterfaceMessage &mes
if (message.messageType() == Zigbee::MessageTypeStatus) {
// We have a status message for the current reply
m_currentReply->setStatusMessage(message);
qCDebug(dcZigbeeController()) << "Current request" << m_currentReply->request().description() << "status message received";
// TODO: check if success, if not, finish reply
} else if (message.messageType() == m_currentReply->request().expectedAdditionalMessageType()) {
} else if (m_currentReply->request().expectsAdditionalMessage() &&
message.messageType() == m_currentReply->request().expectedAdditionalMessageType()) {
m_currentReply->setAdditionalMessage(message);
qCDebug(dcZigbeeController()) << "Current request" << m_currentReply->request().description() << "additional message received";
} else {
// Not a reply related message
qCDebug(dcZigbeeController()) << "Current request" << m_currentReply->request().description() << "but not related message received";
emit messageReceived(message);
return;
}
// Check if request is complete
if (m_currentReply->isComplete()) {
qCDebug(dcZigbeeController()) << "Current request" << m_currentReply->request().description() << "is complete!";
m_currentReply->setFinished();
// Note: the request class has to take care about the reply object
m_currentReply = nullptr;
@ -347,10 +355,11 @@ void ZigbeeBridgeController::onMessageReceived(const ZigbeeInterfaceMessage &mes
return;
}
} else {
// Not a reply message
emit messageReceived(message);
}
// Not a reply message
emit messageReceived(message);
}
void ZigbeeBridgeController::onReplyTimeout()

View File

@ -129,7 +129,7 @@ ZigbeeNode *ZigbeeNetwork::getZigbeeNode(quint16 shortAddress) const
return nullptr;
}
ZigbeeNode *ZigbeeNetwork::getZigbeeNode(ZigbeeAddress address) const
ZigbeeNode *ZigbeeNetwork::getZigbeeNode(const ZigbeeAddress &address) const
{
foreach (ZigbeeNode *node, m_nodes) {
if (node->extendedAddress() == address) {
@ -140,6 +140,16 @@ ZigbeeNode *ZigbeeNetwork::getZigbeeNode(ZigbeeAddress address) const
return nullptr;
}
bool ZigbeeNetwork::hasNode(quint16 shortAddress) const
{
return getZigbeeNode(shortAddress) != nullptr;
}
bool ZigbeeNetwork::hasNode(const ZigbeeAddress &address) const
{
return getZigbeeNode(address) != nullptr;
}
void ZigbeeNetwork::saveNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Save current network configuration to" << m_settingsFileName;
@ -149,6 +159,10 @@ void ZigbeeNetwork::saveNetwork()
settings.setValue("channel", channel());
settings.endGroup();
settings.beginGroup("Nodes");
settings.remove("");
settings.endGroup();
settings.beginWriteArray("Nodes");
for (int i = 0; i < nodes().count(); i++) {
settings.setArrayIndex(i);
@ -173,27 +187,38 @@ void ZigbeeNetwork::loadNetwork()
setChannel(settings.value("channel", 0).toUInt());
settings.endGroup();
settings.beginReadArray("Nodes");
for (int i = 0; i < nodes().count(); i++) {
int nodesCount = settings.beginReadArray("Nodes");
for (int i = 0; i < nodesCount; i++) {
settings.setArrayIndex(i);
ZigbeeNode *node = new ZigbeeNode(this);
node->setShortAddress(static_cast<quint16>(settings.value("nwkAddress", 0).toUInt()));
node->setExtendedAddress(ZigbeeAddress(settings.value("ieeeAddress").toString()));
// TODO: load the rest of the node
addNodeInternally(node);
}
settings.endArray();
qCDebug(dcZigbeeNetwork()) << "PAN Id:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId);
qCDebug(dcZigbeeNetwork()) << "Extended PAN Id:" << m_extendedPanId << ZigbeeUtils::convertUint64ToHexString(m_extendedPanId);
qCDebug(dcZigbeeNetwork()) << "Channel" << m_channel;
qCDebug(dcZigbeeNetwork()) << "Nodes:";
qCDebug(dcZigbeeNetwork()) << QStringLiteral("Nodes: (%1)").arg(m_nodes.count());
foreach (ZigbeeNode *node, nodes()) {
qCDebug(dcZigbeeNetwork()) << " - " << node;
}
}
void ZigbeeNetwork::addNode(ZigbeeNode *node)
{
if (hasNode(node->extendedAddress())) {
qCWarning(dcZigbeeNetwork()) << "The node" << node << "has already been added.";
return;
}
m_nodes.append(node);
emit nodeAdded(node);
saveNetwork();
}
void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node)
{
if (m_nodes.contains(node)) {
qCWarning(dcZigbeeNetwork()) << "The node" << node << "has already been added.";
@ -202,7 +227,6 @@ void ZigbeeNetwork::addNode(ZigbeeNode *node)
m_nodes.append(node);
emit nodeAdded(node);
saveNetwork();
}
void ZigbeeNetwork::removeNode(ZigbeeNode *node)
@ -217,6 +241,38 @@ void ZigbeeNetwork::removeNode(ZigbeeNode *node)
saveNetwork();
}
void ZigbeeNetwork::removeNodeInternally(ZigbeeNode *node)
{
if (!m_nodes.contains(node)) {
qCWarning(dcZigbeeNetwork()) << "Try to remove node" << node << "but not in the node list.";
return;
}
m_nodes.removeAll(node);
emit nodeRemoved(node);
node->deleteLater();
}
void ZigbeeNetwork::clearSettings()
{
qCDebug(dcZigbeeNetwork()) << "Clear network settings";
// Reset network configurations
m_extendedPanId = 0;
m_channel = 0;
m_securityConfiguration.clear();
m_nodeType = ZigbeeNode::NodeTypeCoordinator;
qCDebug(dcZigbeeNetwork()) << "Remove zigbee nodes from network";
foreach (ZigbeeNode *node, m_nodes) {
removeNodeInternally(node);
}
qCDebug(dcZigbeeNetwork()) << "Clear network settings" << m_settingsFileName;
QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
settings.clear();
}
void ZigbeeNetwork::setState(ZigbeeNetwork::State state)
{
if (m_state == state)
@ -239,3 +295,4 @@ void ZigbeeNetwork::setError(ZigbeeNetwork::Error error)
m_error = error;
emit errorOccured(m_error);
}

View File

@ -62,8 +62,13 @@ public:
QList<ZigbeeNode *> nodes() const;
ZigbeeNode *coordinatorNode() const;
ZigbeeNode *getZigbeeNode(quint16 shortAddress) const;
ZigbeeNode *getZigbeeNode(ZigbeeAddress address) const;
ZigbeeNode *getZigbeeNode(const ZigbeeAddress &address) const;
bool hasNode(quint16 shortAddress) const;
bool hasNode(const ZigbeeAddress &address) const;
private:
ControllerType m_controllerType = ControlerTypeNxp;
@ -88,7 +93,11 @@ private:
protected:
void addNode(ZigbeeNode *node);
void addNodeInternally(ZigbeeNode *node);
void removeNode(ZigbeeNode *node);
void removeNodeInternally(ZigbeeNode *node);
void clearSettings();
void setState(State state);
void setError(Error error);
@ -112,6 +121,7 @@ signals:
public slots:
virtual void startNetwork() = 0;
virtual void stopNetwork() = 0;
virtual void factoryResetNetwork() = 0;
};

View File

@ -9,21 +9,17 @@
ZigbeeNetworkManager::ZigbeeNetworkManager(QObject *parent) :
ZigbeeNetwork(ZigbeeNetwork::ControlerTypeNxp, parent)
{
// // Create channel mask
// // Note: normal number passed, that specific channel will be used || Bitfield: all channels would be 0x07FFF800
// quint32 channelMask = 0;
// if (channel == 0) {
// qCDebug(dcZigbeeNetwork()) << "Using quitest channel for the zigbee network.";
// } else {
// channelMask |= 1 << (channel);
// qCDebug(dcZigbeeNetwork()) << "Using channel" << channel << "for the zigbee network.";
// }
}
QString ZigbeeNetworkManager::controllerVersion() const
QString ZigbeeNetworkManager::controllerFirmwareVersion() const
{
return m_controllerVersion;
return m_controllerFirmwareVersion;
}
ZigbeeBridgeController *ZigbeeNetworkManager::controller() const
{
return m_controller;
}
bool ZigbeeNetworkManager::networkRunning() const
@ -180,6 +176,7 @@ void ZigbeeNetworkManager::onCommandResetControllerFinished()
}
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
//if (m_startingState == StartingStateReset && !m_networkRunning) setStartingState(StartingStateGetVersion);
}
void ZigbeeNetworkManager::onCommandSoftResetControllerFinished()
@ -205,8 +202,13 @@ void ZigbeeNetworkManager::onCommandErasePersistentDataFinished()
return;
}
m_factoryResetting = false;
qCDebug(dcZigbeeController()) << reply->request().description() << "finished successfully";
if (m_startingState == StartingStateErase) setStartingState(StartingStateReset);
if (m_startingState == StartingStateErase) {
setStartingState(StartingStateReset);
// setState(StateStarting);
}
}
void ZigbeeNetworkManager::onCommandGetVersionFinished()
@ -230,8 +232,8 @@ void ZigbeeNetworkManager::onCommandGetVersionFinished()
quint16 majorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(0, 2));
quint16 minorVersion = ZigbeeUtils::convertByteArrayToUint16(reply->additionalMessage().data().mid(2, 2));
m_controllerVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
qCDebug(dcZigbeeNetwork()) << "Controller version:" << m_controllerVersion;
m_controllerFirmwareVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
qCDebug(dcZigbeeNetwork()) << "Controller version:" << m_controllerFirmwareVersion;
if (m_startingState == StartingStateGetVersion) setStartingState(StartingStateSetPanId);
}
@ -477,6 +479,9 @@ void ZigbeeNetworkManager::processNetworkFormed(const ZigbeeInterfaceMessage &me
qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(extendedAddress);
qCDebug(dcZigbeeNetwork()) << " Channel:" << channel;
qCDebug(dcZigbeeNetwork()) << " Extended PAN ID:" << extendedPanId();
qCDebug(dcZigbeeNetwork()) << " Permit joining" << permitJoining();
m_networkRunning = true;
@ -928,7 +933,6 @@ void ZigbeeNetworkManager::processFactoryNewRestart(const ZigbeeInterfaceMessage
break;
}
qCDebug(dcZigbeeNetwork()) << "Restart finished. Current controller state:" << controllerStatusString;
if (m_startingState == StartingStateReset) setStartingState(StartingStateGetVersion);
}
@ -1002,24 +1006,35 @@ void ZigbeeNetworkManager::processDeviceAnnounce(const ZigbeeInterfaceMessage &m
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(0, 2));
quint64 ieeeAddress = ZigbeeUtils::convertByteArrayToUint64(message.data().mid(2, 8));
quint8 macCapability = static_cast<quint8>(message.data().at(10));
quint8 macCapabilitiesFlag = static_cast<quint8>(message.data().at(10));
qCDebug(dcZigbeeNetwork()) << "Device announced:";
qCDebug(dcZigbeeNetwork()) << " Address:" << ZigbeeUtils::convertUint16ToHexString(shortAddress);
qCDebug(dcZigbeeNetwork()) << " Extended address:" << ZigbeeAddress(ieeeAddress);
qCDebug(dcZigbeeNetwork()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapability);
qCDebug(dcZigbeeNetwork()) << " Mac capabilities:" << ZigbeeUtils::convertByteToHexString(macCapabilitiesFlag);
ZigbeeNode *node = new ZigbeeNode(this);
node->setShortAddress(shortAddress);
node->setExtendedAddress(ZigbeeAddress(ieeeAddress));
node->setMacCapabilitiesFlag(macCapabilitiesFlag);
qCDebug(dcZigbeeNetwork()) << " Node:" << node;
// FIXME: check if node already added, and if we have to update it
// Start node initialization process
addNode(node);
//node->init();
ZigbeeInterfaceReply *reply = nullptr;
reply = m_controller->commandAuthenticateDevice(node->extendedAddress(), securityConfiguration().globalTrustCenterLinkKey());
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandAuthenticateDeviceFinished);
//saveNetwork();
reply = m_controller->commandNodeDescriptorRequest(node->shortAddress());
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandNodeDescriptorRequestFinished);
reply = m_controller->commandSimpleDescriptorRequest(node->shortAddress(), endPoint());
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandSimpleDescriptorRequestFinished);
reply = m_controller->commandPowerDescriptorRequest(node->shortAddress());
connect(reply, &ZigbeeInterfaceReply::finished, this, &ZigbeeNetworkManager::onCommandPowerDescriptorRequestFinished);
}
void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &message)
@ -1029,11 +1044,10 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &
quint8 endPoint = static_cast<quint8>(message.data().at(3));
quint16 clusterId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(4, 2));
quint16 attributeId = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(6, 2));
quint8 attributStatus = static_cast<quint8>(message.data().at(8));
quint8 attributDataType = static_cast<quint8>(message.data().at(9));
quint8 attributDataType = static_cast<quint8>(message.data().at(8));
quint16 attributeSize = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(10, 2));
QByteArray data = message.data().mid(12);
quint16 attributeSize = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(9, 2));
QByteArray data = message.data().mid(11);
Zigbee::DataType dataType = static_cast<Zigbee::DataType>(attributDataType);
qCDebug(dcZigbeeNetwork()) << "Attribute report:";
@ -1042,7 +1056,6 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &
qCDebug(dcZigbeeNetwork()) << " End point:" << ZigbeeUtils::convertByteToHexString(endPoint);
qCDebug(dcZigbeeNetwork()) << " Cluster:" << ZigbeeUtils::clusterIdToString(static_cast<Zigbee::ClusterId>(clusterId));
qCDebug(dcZigbeeNetwork()) << " Attribut id:" << ZigbeeUtils::convertUint16ToHexString(attributeId);
qCDebug(dcZigbeeNetwork()) << " Attribut status:" << ZigbeeUtils::convertByteToHexString(attributStatus);
qCDebug(dcZigbeeNetwork()) << " Attribut data type:" << dataType;
qCDebug(dcZigbeeNetwork()) << " Attribut size:" << attributeSize;
qCDebug(dcZigbeeNetwork()) << " Data:" << ZigbeeUtils::convertByteArrayToHexString(data);
@ -1052,7 +1065,7 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &
qCDebug(dcZigbeeNetwork()) << " Data(converted)" << QString::fromUtf8(data);
break;
case Zigbee::Bool:
qCDebug(dcZigbeeNetwork()) << " Data(converted)" << QVariant(data).toBool();
qCDebug(dcZigbeeNetwork()) << " Data(converted)" << static_cast<bool>(data.at(0));
break;
default:
break;
@ -1064,10 +1077,24 @@ void ZigbeeNetworkManager::processAttributeReport(const ZigbeeInterfaceMessage &
void ZigbeeNetworkManager::processLeaveIndication(const ZigbeeInterfaceMessage &message)
{
quint16 shortAddress = ZigbeeUtils::convertByteArrayToUint16(message.data().mid(0, 2));
quint8 rejoining = static_cast<quint8>(message.data().at(2));
QByteArray data = message.data();
quint64 extendedAddress = 0;
bool rejoining = 0;
QDataStream stream(&data, QIODevice::ReadOnly);
stream >> extendedAddress;
stream >> rejoining;
qCDebug(dcZigbeeNetwork()) << "Node leaving:" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << rejoining;
ZigbeeAddress address(extendedAddress);
// ZigbeeAddress extendedAddress = ZigbeeAddress(ZigbeeUtils::convertByteArrayToUint64(message.data().mid(0, 8)));
// quint8 rejoining = static_cast<quint8>(message.data().at(9));
qCDebug(dcZigbeeNetwork()) << "Node leaving indication:" << address.toString() << "rejoining:" << rejoining;
ZigbeeNode *node = getZigbeeNode(address);
if (node) {
removeNode(node);
}
// TODO: remove node
}
@ -1094,20 +1121,26 @@ void ZigbeeNetworkManager::processRestartProvisioned(const ZigbeeInterfaceMessag
}
if (m_startingState == StartingStateReset) {
qCDebug(dcZigbeeNetwork()) << "Reset finished.";
if (m_networkRunning) {
qCDebug(dcZigbeeNetwork()) << "Reset finished. Network already running. No need to set it up";
setStartingState(StartingStateGetPermitJoinStatus);
} else {
qCDebug(dcZigbeeNetwork()) << "Reset finished. Set up network";
setStartingState(StartingStateGetVersion);
}
}
}
void ZigbeeNetworkManager::startNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Start network...";
if (m_controller) {
qCDebug(dcZigbeeNetwork()) << "Clean up old controller...";
delete m_controller;
m_controller = nullptr;
}
qCDebug(dcZigbeeNetwork()) << "Create new controller...";
m_controller = new ZigbeeBridgeController(this);
connect(m_controller, &ZigbeeBridgeController::messageReceived, this, &ZigbeeNetworkManager::onMessageReceived);
connect(m_controller, &ZigbeeBridgeController::availableChanged, this, &ZigbeeNetworkManager::onControllerAvailableChanged);
@ -1118,14 +1151,23 @@ void ZigbeeNetworkManager::startNetwork()
setError(ErrorHardwareUnavailable);
} else {
// Reset
setState(StateStarting);
setStartingState(StartingStateReset);
setState(StateStarting);
}
}
void ZigbeeNetworkManager::stopNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Stopping network...";
setState(StateStopping);
if (m_controller) {
delete m_controller;
m_controller = nullptr;
}
setStartingState(StartingStateNone);
setState(StateDisconnected);
setError(ErrorNoError);
}
void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &message)
@ -1162,7 +1204,7 @@ void ZigbeeNetworkManager::onMessageReceived(const ZigbeeInterfaceMessage &messa
processRestartProvisioned(message);
break;
default:
qCDebug(dcZigbeeController()) << "Message received:" << message;
qCWarning(dcZigbeeController()) << "Unhandled message received:" << message;
break;
}
}
@ -1171,6 +1213,11 @@ void ZigbeeNetworkManager::onControllerAvailableChanged(bool available)
{
qCDebug(dcZigbeeNetwork()) << "Hardware controller is" << (available ? "now available" : "not available");
if (m_factoryResetting && !available) {
setStartingState(StartingStateReset);
return;
}
if (!available) {
setError(ErrorHardwareUnavailable);
setState(StateDisconnected);
@ -1183,3 +1230,12 @@ void ZigbeeNetworkManager::onControllerAvailableChanged(bool available)
}
void ZigbeeNetworkManager::factoryResetNetwork()
{
qCDebug(dcZigbeeNetwork()) << "Factory reset network and forgett all information. This cannot be undone.";
clearSettings();
setState(StateStarting);
setStartingState(StartingStateErase);
}

View File

@ -14,7 +14,10 @@ class ZigbeeNetworkManager : public ZigbeeNetwork
public:
explicit ZigbeeNetworkManager(QObject *parent = nullptr);
QString controllerVersion() const;
QString controllerFirmwareVersion() const;
// Note: temporary public available for debugging
ZigbeeBridgeController *controller() const;
bool networkRunning() const;
@ -41,13 +44,16 @@ private:
};
ZigbeeBridgeController *m_controller = nullptr;
QString m_controllerVersion;
QString m_controllerFirmwareVersion;
StartingState m_startingState = StartingStateNone;
void setStartingState(StartingState state);
QList<ZigbeeNode *> m_uninitializedNodes;
bool m_permitJoining = false;
bool m_networkRunning = false;
bool m_factoryResetting = false;
signals:
void permitJoiningChanged(bool permitJoining);
@ -98,6 +104,7 @@ private slots:
public slots:
void startNetwork() override;
void stopNetwork() override;
void factoryResetNetwork() override;
};

View File

@ -31,6 +31,11 @@ void ZigbeeSecurityConfiguration::setGlobalTrustCenterlinkKey(const QString &glo
m_globalTrustCenterLinkKey = globalTrustCenterLinkKey;
}
void ZigbeeSecurityConfiguration::clear()
{
m_networkKey.clear();
}
bool ZigbeeSecurityConfiguration::operator==(const ZigbeeSecurityConfiguration &other) const
{
return m_networkKey == other.networkKey() && m_globalTrustCenterLinkKey == other.globalTrustCenterLinkKey();

View File

@ -15,6 +15,8 @@ public:
QString globalTrustCenterLinkKey() const;
void setGlobalTrustCenterlinkKey(const QString & globalTrustCenterLinkKey);
void clear();
bool operator==(const ZigbeeSecurityConfiguration &other) const;
bool operator!=(const ZigbeeSecurityConfiguration &other) const;