Merge PR #15: Add develco profile and manufacturer and manufacturer specific cluster methods

This commit is contained in:
Jenkins nymea 2021-06-30 12:42:38 +02:00
commit 0a63e2f101
10 changed files with 74 additions and 18 deletions

View File

@ -34,8 +34,26 @@ ZigbeeClusterBinaryInput::ZigbeeClusterBinaryInput(ZigbeeNetwork *network, Zigbe
} }
bool ZigbeeClusterBinaryInput::presentValue() const
{
return m_presentValue;
}
void ZigbeeClusterBinaryInput::setAttribute(const ZigbeeClusterAttribute &attribute) void ZigbeeClusterBinaryInput::setAttribute(const ZigbeeClusterAttribute &attribute)
{ {
qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(attribute.id()) << attribute.dataType(); qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(attribute.id()) << attribute.dataType();
updateOrAddAttribute(attribute); updateOrAddAttribute(attribute);
// Parse the information for convenience
if (attribute.id() == AttributePresentValue) {
bool valueOk = false;
bool value = attribute.dataType().toBool(&valueOk);
if (valueOk) {
m_presentValue = value;
qCDebug(dcZigbeeCluster()) << "Binary input state changed on" << m_node << m_endpoint << this << m_presentValue;
emit presentValueChanged(m_presentValue);
} else {
qCWarning(dcZigbeeCluster()) << "Failed to parse attribute data" << m_node << m_endpoint << this << attribute;
}
}
} }

View File

@ -55,7 +55,14 @@ public:
explicit ZigbeeClusterBinaryInput(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); explicit ZigbeeClusterBinaryInput(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
bool presentValue() const;
signals:
void presentValueChanged(bool presentValue);
private: private:
bool m_presentValue = false;
void setAttribute(const ZigbeeClusterAttribute &attribute) override; void setAttribute(const ZigbeeClusterAttribute &attribute) override;
}; };

View File

@ -51,6 +51,11 @@ void ZigbeeClusterIlluminanceMeasurment::setAttribute(const ZigbeeClusterAttribu
bool valueOk = false; bool valueOk = false;
quint16 value = attribute.dataType().toUInt16(&valueOk); quint16 value = attribute.dataType().toUInt16(&valueOk);
if (valueOk) { if (valueOk) {
if (value == 0xffff) {
qCDebug(dcZigbeeCluster()) << m_node << m_endpoint << this << "received invalid measurement value. Not updating the attribute.";
return;
}
m_illuminance = value; m_illuminance = value;
qCDebug(dcZigbeeCluster()) << "Illuminance changed on" << m_node << m_endpoint << this << m_illuminance << "lux"; qCDebug(dcZigbeeCluster()) << "Illuminance changed on" << m_node << m_endpoint << this << m_illuminance << "lux";
emit illuminanceChanged(m_illuminance); emit illuminanceChanged(m_illuminance);

View File

@ -56,6 +56,11 @@ void ZigbeeClusterPressureMeasurement::setAttribute(const ZigbeeClusterAttribute
bool valueOk = false; bool valueOk = false;
qint16 value = attribute.dataType().toInt16(&valueOk); qint16 value = attribute.dataType().toInt16(&valueOk);
if (valueOk) { if (valueOk) {
if (value == static_cast<qint16>(0x8000)) {
qCDebug(dcZigbeeCluster()) << m_node << m_endpoint << this << "received invalid measurement value. Not updating the attribute.";
return;
}
m_pressure = value / 10.0; m_pressure = value / 10.0;
qCDebug(dcZigbeeCluster()) << "Pressure changed on" << m_node << m_endpoint << this << m_pressure << "kPa"; qCDebug(dcZigbeeCluster()) << "Pressure changed on" << m_node << m_endpoint << this << m_pressure << "kPa";
emit pressureChanged(m_pressure); emit pressureChanged(m_pressure);
@ -64,6 +69,11 @@ void ZigbeeClusterPressureMeasurement::setAttribute(const ZigbeeClusterAttribute
bool valueOk = false; bool valueOk = false;
qint16 value = attribute.dataType().toInt16(&valueOk); qint16 value = attribute.dataType().toInt16(&valueOk);
if (valueOk) { if (valueOk) {
if (value == static_cast<qint16>(0x8000)) {
qCDebug(dcZigbeeCluster()) << m_node << m_endpoint << this << "received invalid measurement value. Not updating the attribute.";
return;
}
m_pressureScaled = value / 10.0; m_pressureScaled = value / 10.0;
qCDebug(dcZigbeeCluster()) << "Pressure scaled changed on" << m_node << m_endpoint << this << m_pressureScaled << "Pa"; qCDebug(dcZigbeeCluster()) << "Pressure scaled changed on" << m_node << m_endpoint << this << m_pressureScaled << "Pa";
emit pressureScaledChanged(m_pressureScaled); emit pressureScaledChanged(m_pressureScaled);

View File

@ -51,6 +51,11 @@ void ZigbeeClusterRelativeHumidityMeasurement::setAttribute(const ZigbeeClusterA
bool valueOk = false; bool valueOk = false;
quint16 value = attribute.dataType().toUInt16(&valueOk); quint16 value = attribute.dataType().toUInt16(&valueOk);
if (valueOk) { if (valueOk) {
if (value == 0xffff) {
qCDebug(dcZigbeeCluster()) << m_node << m_endpoint << this << "received invalid measurement value. Not updating the attribute.";
return;
}
m_humidity = value / 100.0; m_humidity = value / 100.0;
qCDebug(dcZigbeeCluster()) << "Humidity changed on" << m_node << m_endpoint << this << m_humidity << "%"; qCDebug(dcZigbeeCluster()) << "Humidity changed on" << m_node << m_endpoint << this << m_humidity << "%";
emit humidityChanged(m_humidity); emit humidityChanged(m_humidity);

View File

@ -51,6 +51,11 @@ void ZigbeeClusterTemperatureMeasurement::setAttribute(const ZigbeeClusterAttrib
bool valueOk = false; bool valueOk = false;
qint16 value = attribute.dataType().toInt16(&valueOk); qint16 value = attribute.dataType().toInt16(&valueOk);
if (valueOk) { if (valueOk) {
if (value == static_cast<qint16>(0x8000)) {
qCDebug(dcZigbeeCluster()) << m_node << m_endpoint << this << "received invalid measurement value. Not updating the attribute.";
return;
}
m_temperature = value / 100.0; m_temperature = value / 100.0;
qCDebug(dcZigbeeCluster()) << "Temperature changed on" << m_node << m_endpoint << this << m_temperature << "°C"; qCDebug(dcZigbeeCluster()) << "Temperature changed on" << m_node << m_endpoint << this << m_temperature << "°C";
emit temperatureChanged(m_temperature); emit temperatureChanged(m_temperature);

View File

@ -96,7 +96,7 @@ void ZigbeeCluster::setAttribute(const ZigbeeClusterAttribute &attribute)
updateOrAddAttribute(attribute); updateOrAddAttribute(attribute);
} }
ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes) ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes, quint16 manufacturerCode)
{ {
qCDebug(dcZigbeeCluster()) << "Read attributes from" << m_node << m_endpoint << this << attributes; qCDebug(dcZigbeeCluster()) << "Read attributes from" << m_node << m_endpoint << this << attributes;
@ -108,10 +108,10 @@ ZigbeeClusterReply *ZigbeeCluster::readAttributes(QList<quint16> attributes)
stream << attribute; stream << attribute;
} }
return executeGlobalCommand(ZigbeeClusterLibrary::CommandReadAttributes, payload); return executeGlobalCommand(ZigbeeClusterLibrary::CommandReadAttributes, payload, manufacturerCode);
} }
ZigbeeClusterReply *ZigbeeCluster::writeAttributes(QList<ZigbeeClusterLibrary::WriteAttributeRecord> writeAttributeRecords) ZigbeeClusterReply *ZigbeeCluster::writeAttributes(QList<ZigbeeClusterLibrary::WriteAttributeRecord> writeAttributeRecords, quint16 manufacturerCode)
{ {
qCDebug(dcZigbeeCluster()) << "Write attributes on" << m_node << m_endpoint << this; qCDebug(dcZigbeeCluster()) << "Write attributes on" << m_node << m_endpoint << this;
QByteArray payload; QByteArray payload;
@ -119,10 +119,10 @@ ZigbeeClusterReply *ZigbeeCluster::writeAttributes(QList<ZigbeeClusterLibrary::W
payload += ZigbeeClusterLibrary::buildWriteAttributeRecord(writeAttributeRecord); payload += ZigbeeClusterLibrary::buildWriteAttributeRecord(writeAttributeRecord);
} }
return executeGlobalCommand(ZigbeeClusterLibrary::CommandWriteAttributes, payload); return executeGlobalCommand(ZigbeeClusterLibrary::CommandWriteAttributes, payload, manufacturerCode);
} }
ZigbeeClusterReply *ZigbeeCluster::configureReporting(QList<ZigbeeClusterLibrary::AttributeReportingConfiguration> reportingConfigurations) ZigbeeClusterReply *ZigbeeCluster::configureReporting(QList<ZigbeeClusterLibrary::AttributeReportingConfiguration> reportingConfigurations, quint16 manufacturerCode)
{ {
qCDebug(dcZigbeeCluster()) << "Configure reporting on" << m_node << m_endpoint << this << reportingConfigurations; qCDebug(dcZigbeeCluster()) << "Configure reporting on" << m_node << m_endpoint << this << reportingConfigurations;
@ -131,11 +131,11 @@ ZigbeeClusterReply *ZigbeeCluster::configureReporting(QList<ZigbeeClusterLibrary
payload += ZigbeeClusterLibrary::buildAttributeReportingConfiguration(reportingConfiguration); payload += ZigbeeClusterLibrary::buildAttributeReportingConfiguration(reportingConfiguration);
} }
return executeGlobalCommand(ZigbeeClusterLibrary::CommandConfigureReporting, payload); return executeGlobalCommand(ZigbeeClusterLibrary::CommandConfigureReporting, payload, manufacturerCode);
} }
ZigbeeClusterReply *ZigbeeCluster::executeGlobalCommand(quint8 command, const QByteArray &payload) ZigbeeClusterReply *ZigbeeCluster::executeGlobalCommand(quint8 command, const QByteArray &payload, quint16 manufacturerCode)
{ {
// Build the request // Build the request
ZigbeeNetworkRequest request = createGeneralRequest(); ZigbeeNetworkRequest request = createGeneralRequest();
@ -145,7 +145,12 @@ ZigbeeClusterReply *ZigbeeCluster::executeGlobalCommand(quint8 command, const QB
// Note: for basic commands the frame control files has to be zero accoring to spec ZCL 2.4.1.1 // Note: for basic commands the frame control files has to be zero accoring to spec ZCL 2.4.1.1
ZigbeeClusterLibrary::FrameControl frameControl; ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeGlobal; frameControl.frameType = ZigbeeClusterLibrary::FrameTypeGlobal;
frameControl.manufacturerSpecific = false; if (manufacturerCode != 0) {
frameControl.manufacturerSpecific = true;
} else {
frameControl.manufacturerSpecific = false;
}
if (m_direction == Direction::Server) { if (m_direction == Direction::Server) {
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer; frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
} else { } else {
@ -157,6 +162,9 @@ ZigbeeClusterReply *ZigbeeCluster::executeGlobalCommand(quint8 command, const QB
ZigbeeClusterLibrary::Header header; ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl; header.frameControl = frameControl;
header.command = command; header.command = command;
if (manufacturerCode != 0) {
header.manufacturerCode = manufacturerCode;
}
header.transactionSequenceNumber = m_transactionSequenceNumber++; header.transactionSequenceNumber = m_transactionSequenceNumber++;
// Put them together // Put them together
@ -186,7 +194,6 @@ ZigbeeClusterReply *ZigbeeCluster::executeGlobalCommand(quint8 command, const QB
return zclReply; return zclReply;
} }
ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame) ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame)
{ {
ZigbeeClusterReply *zclReply = new ZigbeeClusterReply(request, frame, this); ZigbeeClusterReply *zclReply = new ZigbeeClusterReply(request, frame, this);
@ -394,7 +401,7 @@ void ZigbeeCluster::finishZclReply(ZigbeeClusterReply *zclReply)
m_pendingReplies.remove(zclReply->transactionSequenceNumber()); m_pendingReplies.remove(zclReply->transactionSequenceNumber());
qCDebug(dcZigbeeCluster()) << "ZigbeeClusterReply finished" << zclReply->request() << zclReply->requestFrame() << zclReply->responseFrame(); qCDebug(dcZigbeeCluster()) << "ZigbeeClusterReply finished" << zclReply->request() << zclReply->requestFrame() << zclReply->responseFrame();
// FIXME: Set the status // FIXME: Set the status
zclReply->finished(); emit zclReply->finished();
} }
void ZigbeeCluster::processDataIndication(ZigbeeClusterLibrary::Frame frame) void ZigbeeCluster::processDataIndication(ZigbeeClusterLibrary::Frame frame)

View File

@ -90,12 +90,9 @@ public:
ZigbeeClusterAttribute attribute(quint16 attributeId); ZigbeeClusterAttribute attribute(quint16 attributeId);
// ZCL global commands // ZCL global commands
ZigbeeClusterReply *readAttributes(QList<quint16> attributes); ZigbeeClusterReply *readAttributes(QList<quint16> attributes, quint16 manufacturerCode = 0x0000);
ZigbeeClusterReply *writeAttributes(QList<ZigbeeClusterLibrary::WriteAttributeRecord> writeAttributeRecords); ZigbeeClusterReply *writeAttributes(QList<ZigbeeClusterLibrary::WriteAttributeRecord> writeAttributeRecords, quint16 manufacturerCode = 0x0000);
ZigbeeClusterReply *configureReporting(QList<ZigbeeClusterLibrary::AttributeReportingConfiguration> reportingConfigurations); ZigbeeClusterReply *configureReporting(QList<ZigbeeClusterLibrary::AttributeReportingConfiguration> reportingConfigurations, quint16 manufacturerCode = 0x0000);
protected: protected:
ZigbeeNetwork *m_network = nullptr; ZigbeeNetwork *m_network = nullptr;
@ -112,7 +109,8 @@ protected:
QHash<quint8, ZigbeeClusterReply *> m_pendingReplies; QHash<quint8, ZigbeeClusterReply *> m_pendingReplies;
// Global commands // Global commands
ZigbeeClusterReply *executeGlobalCommand(quint8 command, const QByteArray &payload = QByteArray()); ZigbeeClusterReply *executeGlobalCommand(quint8 command, const QByteArray &payload = QByteArray(), quint16 manufacturerCode = 0x0000);
ZigbeeClusterReply *executeManufacturerSpecificGlobalCommand(quint8 command, quint16 manufacturerCode, const QByteArray &payload = QByteArray());
// Cluster specific // Cluster specific
ZigbeeClusterReply *createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame); ZigbeeClusterReply *createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame);

View File

@ -55,6 +55,7 @@ public:
ZigbeeProfilePersonalHomeHospitalCare = 0x0108, ZigbeeProfilePersonalHomeHospitalCare = 0x0108,
ZigbeeProfileAdvancedMetering = 0x0109, ZigbeeProfileAdvancedMetering = 0x0109,
ZigbeeProfileLightLink = 0xC05E, ZigbeeProfileLightLink = 0xC05E,
ZigbeeProfileDevelco = 0xC0C9,
ZigbeeProfileGreenPower = 0xA1E0 ZigbeeProfileGreenPower = 0xA1E0
}; };
Q_ENUM(ZigbeeProfile) Q_ENUM(ZigbeeProfile)
@ -286,6 +287,7 @@ public:
Chipcon = 0x1001, Chipcon = 0x1001,
Ember = 0x1003, Ember = 0x1003,
Philips = 0x100b, Philips = 0x100b,
Develco = 0x1015,
Ikea = 0x117C, Ikea = 0x117C,
FeiBit = 0x117E FeiBit = 0x117E
}; };

View File

@ -53,7 +53,6 @@ ZigbeeNetwork::ZigbeeNetwork(const QUuid &networkUuid, QObject *parent) :
} }
}); });
m_reachableRefreshTimer = new QTimer(this); m_reachableRefreshTimer = new QTimer(this);
m_reachableRefreshTimer->setInterval(120000); m_reachableRefreshTimer->setInterval(120000);
m_reachableRefreshTimer->setSingleShot(false); m_reachableRefreshTimer->setSingleShot(false);