From af26efac1712fef8ab769a87546a1cfc8688f95c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 11 Nov 2020 15:50:28 +0100 Subject: [PATCH] Add pressure cluster and improve nxp backend APS handling --- libnymea-zigbee/backends/nxp/interface/nxp.h | 2 + .../nxp/zigbeebridgecontrollernxp.cpp | 22 +++- .../backends/nxp/zigbeebridgecontrollernxp.h | 10 ++ .../backends/nxp/zigbeenetworknxp.cpp | 14 +++ .../backends/nxp/zigbeenetworknxp.h | 2 +- libnymea-zigbee/libnymea-zigbee.pro | 2 + libnymea-zigbee/loggingcategory.cpp | 1 + libnymea-zigbee/loggingcategory.h | 1 + .../general/zigbeeclusterpowerconfiguration.h | 4 +- .../zigbeeclusteroccupancysensing.h | 2 + .../zigbeeclusterpressuremeasurement.cpp | 68 ++++++++++ .../zigbeeclusterpressuremeasurement.h | 78 ++++++++++++ libnymea-zigbee/zigbeeaddress.h | 2 +- libnymea-zigbee/zigbeenetwork.cpp | 8 ++ libnymea-zigbee/zigbeenetwork.h | 4 +- libnymea-zigbee/zigbeenetworkdatabase.h | 2 + libnymea-zigbee/zigbeenode.cpp | 116 +++++++++++------- libnymea-zigbee/zigbeenodeendpoint.cpp | 3 + libnymea-zigbee/zigbeenodeendpoint.h | 1 + 19 files changed, 291 insertions(+), 51 deletions(-) create mode 100644 libnymea-zigbee/zcl/measurement/zigbeeclusterpressuremeasurement.cpp create mode 100644 libnymea-zigbee/zcl/measurement/zigbeeclusterpressuremeasurement.h diff --git a/libnymea-zigbee/backends/nxp/interface/nxp.h b/libnymea-zigbee/backends/nxp/interface/nxp.h index 5785321..4fbe95d 100644 --- a/libnymea-zigbee/backends/nxp/interface/nxp.h +++ b/libnymea-zigbee/backends/nxp/interface/nxp.h @@ -57,6 +57,8 @@ public: NotificationNetworkStarted = 0x7E, NotificationApsDataConfirm = 0x80, NotificationApsDataIndication = 0x81, + NotificationNodeJoined = 0x90, + NotificationNodeLeft = 0x91, NotificationDebugMessage = 0xFE }; Q_ENUM(Notification) diff --git a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp index e385d9f..58cbd86 100644 --- a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp +++ b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.cpp @@ -328,7 +328,7 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestEnqueueSendDataGroup( payloadStream << profileId; payloadStream << clusterId; payloadStream << sourceEndpoint; - payloadStream << static_cast(0x00); // Network and application layer security + payloadStream << static_cast(SecurityModeUnsecure); payloadStream << radius; payloadStream << static_cast(asdu.size()); for (int i = 0; i < asdu.size(); i++) { @@ -364,7 +364,7 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestEnqueueSendDataShortA payloadStream << profileId; payloadStream << clusterId; payloadStream << sourceEndpoint; - payloadStream << static_cast(0x00); // Network and application layer security + payloadStream << static_cast(SecurityModeUnsecure); payloadStream << radius; payloadStream << static_cast(asdu.size()); for (int i = 0; i < asdu.size(); i++) { @@ -400,7 +400,7 @@ ZigbeeInterfaceNxpReply *ZigbeeBridgeControllerNxp::requestEnqueueSendDataIeeeAd payloadStream << profileId; payloadStream << clusterId; payloadStream << sourceEndpoint; - payloadStream << static_cast(0x00); // Network and application layer security + payloadStream << static_cast(SecurityModeUnsecure); payloadStream << radius; payloadStream << static_cast(asdu.size()); for (int i = 0; i < asdu.size(); i++) { @@ -559,6 +559,18 @@ void ZigbeeBridgeControllerNxp::onInterfacePackageReceived(const QByteArray &pac emit apsDataIndicationReceived(indication); break; } + case Nxp::NotificationNodeJoined: { + + break; + } + case Nxp::NotificationNodeLeft: { + QDataStream stream(&payload, QIODevice::ReadOnly); + stream.setByteOrder(QDataStream::LittleEndian); + quint64 ieeeAddress; quint8 rejoining; + stream >> ieeeAddress >> rejoining; + emit nodeLeft(ZigbeeAddress(ieeeAddress), static_cast(rejoining)); + break; + } case Nxp::NotificationDebugMessage: { if (payload.isEmpty()) { qCWarning(dcZigbeeController()) << "Received empty debug log notification"; @@ -567,9 +579,9 @@ void ZigbeeBridgeControllerNxp::onInterfacePackageReceived(const QByteArray &pac Nxp::LogLevel logLevel = static_cast(payload.at(0)); QString debugMessage = QString::fromLocal8Bit(payload.right(payload.length() - 1)); if (static_cast(logLevel) <= static_cast(Nxp::LogLevelWarning)) { - qCWarning(dcZigbeeController()) << "***** Controller DEBUG *****" << logLevel << debugMessage; + qCWarning(dcZigbeeControllerDebug()) << "====== Controller DEBUG" << logLevel << debugMessage; } else { - qCDebug(dcZigbeeController()) << "***** Controller DEBUG *****" << logLevel << debugMessage; + qCDebug(dcZigbeeControllerDebug()) << "====== Controller DEBUG" << logLevel << debugMessage; } break; } diff --git a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h index 7981484..2c45dcf 100644 --- a/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h +++ b/libnymea-zigbee/backends/nxp/zigbeebridgecontrollernxp.h @@ -61,6 +61,15 @@ public: }; Q_ENUM(ControllerState) + enum SecurityMode { + SecurityModeUnsecure = 0x00, + SecurityModeSecure = 0x01, + SecurityModeSecureNwk = 0x02, + SecurityModeExtendedNonde = 0x10, + SecurityModeWildProfile = 0x20 + }; + Q_ENUM(SecurityMode) + ControllerState controllerState() const; void refreshControllerState(); @@ -91,6 +100,7 @@ public: signals: void controllerStateChanged(ControllerState controllerState); void interfaceNotificationReceived(Nxp::Notification notification, const QByteArray &data); + void nodeLeft(const ZigbeeAddress &address, bool rejoining); private: ZigbeeInterfaceNxp *m_interface = nullptr; diff --git a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp index ef08485..88625ac 100644 --- a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp +++ b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp @@ -42,6 +42,7 @@ ZigbeeNetworkNxp::ZigbeeNetworkNxp(const QUuid &networkUuid, QObject *parent) : connect(m_controller, &ZigbeeBridgeControllerNxp::controllerStateChanged, this, &ZigbeeNetworkNxp::onControllerStateChanged); connect(m_controller, &ZigbeeBridgeControllerNxp::apsDataConfirmReceived, this, &ZigbeeNetworkNxp::onApsDataConfirmReceived); connect(m_controller, &ZigbeeBridgeControllerNxp::apsDataIndicationReceived, this, &ZigbeeNetworkNxp::onApsDataIndicationReceived); + connect(m_controller, &ZigbeeBridgeControllerNxp::nodeLeft, this, &ZigbeeNetworkNxp::onNodeLeftIndication); connect(m_controller, &ZigbeeBridgeControllerNxp::canUpdateChanged, this, [](bool canUpdate){ if (canUpdate) { qCDebug(dcZigbeeNetwork()) << "The controller of this network can be updated."; @@ -566,6 +567,19 @@ void ZigbeeNetworkNxp::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress iee node->startInitialization(); } +void ZigbeeNetworkNxp::onNodeLeftIndication(const ZigbeeAddress &ieeeAddress, bool rejoining) +{ + qCDebug(dcZigbeeNetwork()) << "Received node left indication" << ieeeAddress.toString() << "rejoining:" << rejoining; + if (!hasNode(ieeeAddress)) { + qCWarning(dcZigbeeNetwork()) << "Unknown node left the network" << ieeeAddress.toString(); + return; + } + + ZigbeeNode *node = getZigbeeNode(ieeeAddress); + qCDebug(dcZigbeeNetwork()) << node << "left the network"; + removeNode(node); +} + void ZigbeeNetworkNxp::startNetwork() { loadNetwork(); diff --git a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h index 1c28582..33504dd 100644 --- a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h +++ b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h @@ -73,7 +73,7 @@ private slots: void onApsDataIndicationReceived(const Zigbee::ApsdeDataIndication &indication); void onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities); - + void onNodeLeftIndication(const ZigbeeAddress &ieeeAddress, bool rejoining); signals: diff --git a/libnymea-zigbee/libnymea-zigbee.pro b/libnymea-zigbee/libnymea-zigbee.pro index 85617e6..f9c783e 100644 --- a/libnymea-zigbee/libnymea-zigbee.pro +++ b/libnymea-zigbee/libnymea-zigbee.pro @@ -25,6 +25,7 @@ SOURCES += \ zcl/lighting/zigbeeclustercolorcontrol.cpp \ zcl/measurement/zigbeeclusterilluminancemeasurment.cpp \ zcl/measurement/zigbeeclusteroccupancysensing.cpp \ + zcl/measurement/zigbeeclusterpressuremeasurement.cpp \ zcl/measurement/zigbeeclusterrelativehumiditymeasurement.cpp \ zcl/measurement/zigbeeclustertemperaturemeasurement.cpp \ zcl/ota/zigbeeclusterota.cpp \ @@ -79,6 +80,7 @@ HEADERS += \ zcl/lighting/zigbeeclustercolorcontrol.h \ zcl/measurement/zigbeeclusterilluminancemeasurment.h \ zcl/measurement/zigbeeclusteroccupancysensing.h \ + zcl/measurement/zigbeeclusterpressuremeasurement.h \ zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h \ zcl/measurement/zigbeeclustertemperaturemeasurement.h \ zcl/ota/zigbeeclusterota.h \ diff --git a/libnymea-zigbee/loggingcategory.cpp b/libnymea-zigbee/loggingcategory.cpp index 7056392..a8ad5e7 100644 --- a/libnymea-zigbee/loggingcategory.cpp +++ b/libnymea-zigbee/loggingcategory.cpp @@ -37,5 +37,6 @@ Q_LOGGING_CATEGORY(dcZigbeeController, "ZigbeeController") Q_LOGGING_CATEGORY(dcZigbeeDeviceObject, "ZigbeeDeviceObject") Q_LOGGING_CATEGORY(dcZigbeeAdapterMonitor, "ZigbeeAdapterMonitor") Q_LOGGING_CATEGORY(dcZigbeeClusterLibrary, "ZigbeeClusterLibrary") +Q_LOGGING_CATEGORY(dcZigbeeControllerDebug, "ZigbeeControllerDebug") Q_LOGGING_CATEGORY(dcZigbeeNetworkDatabase, "ZigbeeNetworkDatabase") Q_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic, "ZigbeeInterfaceTraffic") diff --git a/libnymea-zigbee/loggingcategory.h b/libnymea-zigbee/loggingcategory.h index a6d471d..327559c 100644 --- a/libnymea-zigbee/loggingcategory.h +++ b/libnymea-zigbee/loggingcategory.h @@ -41,6 +41,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcZigbeeController) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeDeviceObject) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeAdapterMonitor) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeClusterLibrary) +Q_DECLARE_LOGGING_CATEGORY(dcZigbeeControllerDebug) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeNetworkDatabase) Q_DECLARE_LOGGING_CATEGORY(dcZigbeeInterfaceTraffic) diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.h b/libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.h index 7e298f7..b08bc48 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.h +++ b/libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.h @@ -49,14 +49,17 @@ public: // Mains information AttributeMainsVoltage = 0x0000, AttributeMainsFrequency = 0x0001, + // Mains settings AttributeMainsAlarmMask = 0x0010, AttributeMainsVoltageMinThreshold = 0x0011, AttributeMainsVoltageMaxThreshold = 0x0012, AttributeMainsVoltageDwellTripPoint = 0x0013, + // Battery information AttributeBatteryVoltage = 0x0020, AttributeBatteryPercentageRemaining = 0x0021, + // Battery settings AttributeBatteryManufacturer = 0x0030, AttributeBatterySize = 0x0031, @@ -84,7 +87,6 @@ public: Q_ENUM(MainsAlarmMask) Q_DECLARE_FLAGS(MainsAlarmMaskFlag, MainsAlarmMask) - explicit ZigbeeClusterPowerConfiguration(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); private: diff --git a/libnymea-zigbee/zcl/measurement/zigbeeclusteroccupancysensing.h b/libnymea-zigbee/zcl/measurement/zigbeeclusteroccupancysensing.h index 95cc614..1a89ae7 100644 --- a/libnymea-zigbee/zcl/measurement/zigbeeclusteroccupancysensing.h +++ b/libnymea-zigbee/zcl/measurement/zigbeeclusteroccupancysensing.h @@ -50,10 +50,12 @@ public: // Occupancy sensor information set AttributeOccupancy = 0x0000, AttributeOccupancySensorType = 0x0001, + // PRI configuration set AttributePirOccupiedToUnoccupiedDelay = 0x0010, AttributePirUnoccupiedToOccupiedDelay = 0x0011, AttributePirUnoccupiedToOccupiedThreshold = 0x0012, + // Ultrasonic configuration set AttributeUltrasonicOccupiedToUnoccupiedDelay = 0x0020, AttributeUltrasonicUnoccupiedToOccupiedDelay = 0x0021, diff --git a/libnymea-zigbee/zcl/measurement/zigbeeclusterpressuremeasurement.cpp b/libnymea-zigbee/zcl/measurement/zigbeeclusterpressuremeasurement.cpp new file mode 100644 index 0000000..b0a5871 --- /dev/null +++ b/libnymea-zigbee/zcl/measurement/zigbeeclusterpressuremeasurement.cpp @@ -0,0 +1,68 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "zigbeeclusterpressuremeasurement.h" +#include "zigbeenetworkreply.h" +#include "loggingcategory.h" +#include "zigbeenetwork.h" + +ZigbeeClusterPressureMeasurement::ZigbeeClusterPressureMeasurement(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) : + ZigbeeCluster(network, node, endpoint, ZigbeeClusterLibrary::ClusterIdPressureMeasurement, direction, parent) +{ + +} + +void ZigbeeClusterPressureMeasurement::setAttribute(const ZigbeeClusterAttribute &attribute) +{ + qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast(attribute.id()) << attribute.dataType(); + if (hasAttribute(attribute.id())) { + m_attributes[attribute.id()] = attribute; + emit attributeChanged(attribute); + } else { + m_attributes.insert(attribute.id(), attribute); + emit attributeChanged(attribute); + } + + // Parse the information for convinience + if (attribute.id() == AttributeMeasuredValue) { + bool valueOk = false; + qint16 value = attribute.dataType().toInt16(&valueOk); + if (valueOk) { + double pressure = value / 10.0; + qCDebug(dcZigbeeCluster()) << "Pressure changed on" << m_node << m_endpoint << this << pressure << "kPa"; + emit pressureChanged(pressure); + } + } else if (attribute.id() == AttributeScaledValue) { + bool valueOk = false; + qint16 value = attribute.dataType().toInt16(&valueOk); + if (valueOk) { + double pressureScaled = value / 10.0; + qCDebug(dcZigbeeCluster()) << "Pressure scaled changed on" << m_node << m_endpoint << this << pressureScaled << "Pa"; + emit pressureScaledChanged(pressureScaled); + } + } +} diff --git a/libnymea-zigbee/zcl/measurement/zigbeeclusterpressuremeasurement.h b/libnymea-zigbee/zcl/measurement/zigbeeclusterpressuremeasurement.h new file mode 100644 index 0000000..9002a9e --- /dev/null +++ b/libnymea-zigbee/zcl/measurement/zigbeeclusterpressuremeasurement.h @@ -0,0 +1,78 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea-zigbee. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef ZIGBEECLUSTERPRESSUREMEASUREMENT_H +#define ZIGBEECLUSTERPRESSUREMEASUREMENT_H + +#include +#include "zcl/zigbeecluster.h" +#include "zcl/zigbeeclusterreply.h" + +class ZigbeeNode; +class ZigbeeNetwork; +class ZigbeeNodeEndpoint; +class ZigbeeNetworkReply; + +class ZigbeeClusterPressureMeasurement : public ZigbeeCluster +{ + Q_OBJECT + + friend class ZigbeeNode; + friend class ZigbeeNetwork; + +public: + enum Attribute { + AttributeMeasuredValue = 0x0000, + AttributeMinMeasuredValue = 0x0001, + AttributeMaxMeasuredValue = 0x0002, + AttributeTolerance = 0x0003, + + // Extended pressure measurment information + AttributeScaledValue = 0x0010, + AttributeMinScaledValue = 0x0011, + AttributeMaxScaledValue = 0x0012, + AttributeScaledTolerance = 0x0013, + AttributeScale = 0x0014 + }; + Q_ENUM(Attribute) + + explicit ZigbeeClusterPressureMeasurement(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); + +private: + void setAttribute(const ZigbeeClusterAttribute &attribute) override; + +signals: + // kPa + void pressureChanged(double pressure); + + // Pa + void pressureScaledChanged(double pressure); + + +}; + +#endif // ZIGBEECLUSTERPRESSUREMEASUREMENT_H diff --git a/libnymea-zigbee/zigbeeaddress.h b/libnymea-zigbee/zigbeeaddress.h index 0d1d2c9..29c14a3 100644 --- a/libnymea-zigbee/zigbeeaddress.h +++ b/libnymea-zigbee/zigbeeaddress.h @@ -51,7 +51,7 @@ public: bool operator!=(const ZigbeeAddress &other) const; private: - quint64 m_address; + quint64 m_address = 0; }; diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index bc01f75..d4b14e4 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -422,6 +422,11 @@ ZigbeeNode *ZigbeeNetwork::createNode(quint16 shortAddress, const ZigbeeAddress void ZigbeeNetwork::loadNetwork() { + if (m_networkLoaded) { + qCDebug(dcZigbeeNetwork()) << "Network already loaded"; + return; + } + qCDebug(dcZigbeeNetwork()) << "Loading network from settings directory" << m_settingsDirectory.absolutePath(); if (!m_database) { QString networkDatabaseFileName = m_settingsDirectory.absolutePath() + QDir::separator() + QString("zigbee-network-%1.db").arg(m_networkUuid.toString().remove('{').remove('}')); @@ -434,6 +439,8 @@ void ZigbeeNetwork::loadNetwork() node->setState(ZigbeeNode::StateInitialized); addNodeInternally(node); } + + m_networkLoaded = true; } void ZigbeeNetwork::clearSettings() @@ -462,6 +469,7 @@ void ZigbeeNetwork::clearSettings() // Reset network configurations qCDebug(dcZigbeeNetwork()) << "Clear network properties"; + m_networkLoaded = false; setExtendedPanId(0); setChannel(0); setSecurityConfiguration(ZigbeeSecurityConfiguration()); diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h index 2ce0c0d..2f1009e 100644 --- a/libnymea-zigbee/zigbeenetwork.h +++ b/libnymea-zigbee/zigbeenetwork.h @@ -125,6 +125,8 @@ public: virtual ZigbeeNetworkReply *sendRequest(const ZigbeeNetworkRequest &request) = 0; + void loadNetwork(); + void removeZigbeeNode(const ZigbeeAddress &address); private: @@ -162,6 +164,7 @@ protected: ZigbeeNode *m_coordinatorNode = nullptr; ZigbeeSecurityConfiguration m_securityConfiguration; ZigbeeNetworkDatabase *m_database = nullptr; + bool m_networkLoaded = false; ZigbeeNode *createNode(quint16 shortAddress, const ZigbeeAddress &extendedAddress, QObject *parent); ZigbeeNode *createNode(quint16 shortAddress, const ZigbeeAddress &extendedAddress, quint8 macCapabilities, QObject *parent); @@ -176,7 +179,6 @@ protected: void setPermitJoiningDuration(quint8 duration); void setPermitJoiningRemaining(quint8 remaining); - void loadNetwork(); void clearSettings(); bool hasUninitializedNode(const ZigbeeAddress &address) const; diff --git a/libnymea-zigbee/zigbeenetworkdatabase.h b/libnymea-zigbee/zigbeenetworkdatabase.h index f18f13d..b85f80e 100644 --- a/libnymea-zigbee/zigbeenetworkdatabase.h +++ b/libnymea-zigbee/zigbeenetworkdatabase.h @@ -39,6 +39,8 @@ class ZigbeeNetwork; class ZigbeeNodeEndpoint; class ZigbeeClusterAttribute; +class QSqlDatabase; + class ZigbeeNetworkDatabase : public QObject { Q_OBJECT diff --git a/libnymea-zigbee/zigbeenode.cpp b/libnymea-zigbee/zigbeenode.cpp index ef18a02..6be8641 100644 --- a/libnymea-zigbee/zigbeenode.cpp +++ b/libnymea-zigbee/zigbeenode.cpp @@ -445,24 +445,35 @@ void ZigbeeNode::readManufacturerName(ZigbeeClusterBasic *basicCluster) connect(reply, &ZigbeeClusterReply::finished, this, [this, basicCluster, reply, attributeId](){ if (reply->error() != ZigbeeClusterReply::ErrorNoError) { qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read basic cluster attribute" << attributeId << reply->error(); - } else { - qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; - QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); - if (!attributeStatusRecords.isEmpty()) { - ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first(); - qCDebug(dcZigbeeNode()) << attributeStatusRecord; - basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecord.dataType)); - bool valueOk = false; - QString manufacturerName = attributeStatusRecord.dataType.toString(&valueOk); - if (valueOk) { - endpoints().first()->m_manufacturerName = manufacturerName; - } else { - qCWarning(dcZigbeeNode()) << "Could not convert manufacturer name attribute data to string" << attributeStatusRecord.dataType; - } + if (m_requestRetry < 3) { + m_requestRetry++; + qCDebug(dcZigbeeNode()) << "Retry to read manufacturer name from" << this << basicCluster << m_requestRetry << "/" << "3 attempts."; + readManufacturerName(basicCluster); + } else { + qCWarning(dcZigbeeNode()) << "Failed to read manufacturer name from" << this << basicCluster << "after 3 attempts. Giving up and continue..."; + m_requestRetry = 0; + readModelIdentifier(basicCluster); + } + return; + } + + qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; + QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); + if (!attributeStatusRecords.isEmpty()) { + ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first(); + qCDebug(dcZigbeeNode()) << attributeStatusRecord; + basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecord.dataType)); + bool valueOk = false; + QString manufacturerName = attributeStatusRecord.dataType.toString(&valueOk); + if (valueOk) { + endpoints().first()->m_manufacturerName = manufacturerName; + } else { + qCWarning(dcZigbeeNode()) << "Could not convert manufacturer name attribute data to string" << attributeStatusRecord.dataType; } } // Continue eiterh way with attribute reading + m_requestRetry = 0; readModelIdentifier(basicCluster); }); } @@ -493,24 +504,35 @@ void ZigbeeNode::readModelIdentifier(ZigbeeClusterBasic *basicCluster) connect(reply, &ZigbeeClusterReply::finished, this, [this, basicCluster, reply, attributeId](){ if (reply->error() != ZigbeeClusterReply::ErrorNoError) { qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read basic cluster attribute" << attributeId << reply->error(); - } else { - qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; - QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); - if (!attributeStatusRecords.isEmpty()) { - ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first(); - qCDebug(dcZigbeeNode()) << attributeStatusRecord; - basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecord.dataType)); - bool valueOk = false; - QString modelIdentifier = attributeStatusRecord.dataType.toString(&valueOk); - if (valueOk) { - endpoints().first()->m_modelIdentifier = modelIdentifier; - } else { - qCWarning(dcZigbeeNode()) << "Could not convert model identifier attribute data to string" << attributeStatusRecord.dataType; - } + if (m_requestRetry < 3) { + m_requestRetry++; + qCDebug(dcZigbeeNode()) << "Retry to read model identifier from" << this << basicCluster << m_requestRetry << "/" << "3 attempts."; + readModelIdentifier(basicCluster); + } else { + qCWarning(dcZigbeeNode()) << "Failed to read model identifier from" << this << basicCluster << "after 3 attempts. Giving up and continue..."; + m_requestRetry = 0; + readSoftwareBuildId(basicCluster); + } + return; + } + + qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; + QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); + if (!attributeStatusRecords.isEmpty()) { + ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first(); + qCDebug(dcZigbeeNode()) << attributeStatusRecord; + basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecord.dataType)); + bool valueOk = false; + QString modelIdentifier = attributeStatusRecord.dataType.toString(&valueOk); + if (valueOk) { + endpoints().first()->m_modelIdentifier = modelIdentifier; + } else { + qCWarning(dcZigbeeNode()) << "Could not convert model identifier attribute data to string" << attributeStatusRecord.dataType; } } // Continue eiterh way with attribute reading + m_requestRetry = 0; readSoftwareBuildId(basicCluster); }); } @@ -523,20 +545,30 @@ void ZigbeeNode::readSoftwareBuildId(ZigbeeClusterBasic *basicCluster) connect(reply, &ZigbeeClusterReply::finished, this, [this, basicCluster, reply, attributeId](){ if (reply->error() != ZigbeeClusterReply::ErrorNoError) { qCWarning(dcZigbeeNode()) << "Error occured during initialization of" << this << "Failed to read basic cluster attribute" << attributeId << reply->error(); - } else { - qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; - QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); - if (!attributeStatusRecords.isEmpty()) { - ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first(); - qCDebug(dcZigbeeNode()) << attributeStatusRecord; - basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecord.dataType)); - bool valueOk = false; - QString softwareBuildId = attributeStatusRecord.dataType.toString(&valueOk); - if (valueOk) { - endpoints().first()->m_softwareBuildId = softwareBuildId; - } else { - qCWarning(dcZigbeeNode()) << "Could not convert software build id attribute data to string" << attributeStatusRecord.dataType; - } + if (m_requestRetry < 3) { + m_requestRetry++; + qCDebug(dcZigbeeNode()) << "Retry to read model identifier from" << this << basicCluster << m_requestRetry << "/" << "3 attempts."; + readModelIdentifier(basicCluster); + } else { + qCWarning(dcZigbeeNode()) << "Failed to read model identifier from" << this << basicCluster << "after 3 attempts. Giving up and continue..."; + m_requestRetry = 0; + readSoftwareBuildId(basicCluster); + } + return; + } + + qCDebug(dcZigbeeNode()) << "Reading basic cluster attributes finished successfully"; + QList attributeStatusRecords = ZigbeeClusterLibrary::parseAttributeStatusRecords(reply->responseFrame().payload); + if (!attributeStatusRecords.isEmpty()) { + ZigbeeClusterLibrary::ReadAttributeStatusRecord attributeStatusRecord = attributeStatusRecords.first(); + qCDebug(dcZigbeeNode()) << attributeStatusRecord; + basicCluster->setAttribute(ZigbeeClusterAttribute(static_cast(attributeId), attributeStatusRecord.dataType)); + bool valueOk = false; + QString softwareBuildId = attributeStatusRecord.dataType.toString(&valueOk); + if (valueOk) { + endpoints().first()->m_softwareBuildId = softwareBuildId; + } else { + qCWarning(dcZigbeeNode()) << "Could not convert software build id attribute data to string" << attributeStatusRecord.dataType; } } diff --git a/libnymea-zigbee/zigbeenodeendpoint.cpp b/libnymea-zigbee/zigbeenodeendpoint.cpp index 7c56bc1..4b2b39d 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.cpp +++ b/libnymea-zigbee/zigbeenodeendpoint.cpp @@ -194,6 +194,9 @@ ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(ZigbeeClusterLibrary::ClusterId case ZigbeeClusterLibrary::ClusterIdOccupancySensing: return new ZigbeeClusterOccupancySensing(m_network, m_node, this, direction, this); break; + case ZigbeeClusterLibrary::ClusterIdPressureMeasurement: + return new ZigbeeClusterPressureMeasurement(m_network, m_node, this, direction, this); + break; // Colsures case ZigbeeClusterLibrary::ClusterIdDoorLock: diff --git a/libnymea-zigbee/zigbeenodeendpoint.h b/libnymea-zigbee/zigbeenodeendpoint.h index f260162..4937876 100644 --- a/libnymea-zigbee/zigbeenodeendpoint.h +++ b/libnymea-zigbee/zigbeenodeendpoint.h @@ -49,6 +49,7 @@ #include "zcl/measurement/zigbeeclusterilluminancemeasurment.h" #include "zcl/measurement/zigbeeclustertemperaturemeasurement.h" #include "zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h" +#include "zcl/measurement/zigbeeclusterpressuremeasurement.h" #include "zcl/lighting/zigbeeclustercolorcontrol.h"