Add identify and iaszone cluster implementations

pull/7/head
Simon Stürz 2020-05-29 13:55:00 +02:00
parent 9196ff83cf
commit 8105a9082b
11 changed files with 600 additions and 35 deletions

View File

@ -8,9 +8,11 @@ SOURCES += \
backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \
backends/deconz/zigbeebridgecontrollerdeconz.cpp \
backends/deconz/zigbeenetworkdeconz.cpp \
zcl/general/zigbeeclusteridentify.cpp \
zcl/general/zigbeeclusteronoff.cpp \
zcl/measurement/zigbeeclusterrelativehumiditymeasurement.cpp \
zcl/measurement/zigbeeclustertemperaturemeasurement.cpp \
zcl/security/zigbeeclusteriaszone.cpp \
zcl/zigbeecluster.cpp \
zcl/zigbeeclusterattribute.cpp \
zcl/zigbeeclusterlibrary.cpp \
@ -52,9 +54,11 @@ HEADERS += \
backends/deconz/interface/zigbeeinterfacedeconzreply.h \
backends/deconz/zigbeebridgecontrollerdeconz.h \
backends/deconz/zigbeenetworkdeconz.h \
zcl/general/zigbeeclusteridentify.h \
zcl/general/zigbeeclusteronoff.h \
zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h \
zcl/measurement/zigbeeclustertemperaturemeasurement.h \
zcl/security/zigbeeclusteriaszone.h \
zcl/zigbeecluster.h \
zcl/zigbeeclusterattribute.h \
zcl/zigbeeclusterlibrary.h \

View File

@ -0,0 +1,217 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 "zigbeeclusteridentify.h"
#include "zigbeenetworkreply.h"
#include "loggingcategory.h"
#include "zigbeenetwork.h"
#include <QDataStream>
ZigbeeClusterIdentify::ZigbeeClusterIdentify(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdIdentify, direction, parent)
{
}
ZigbeeClusterReply *ZigbeeClusterIdentify::identify(quint16 seconds)
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterIdentify::CommandIdentify;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
// Note: the identify time unit is 0.5 seconds
QByteArray payload = ZigbeeDataType(seconds * 2).data();
// Put them together
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
frame.payload = payload;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
}
ZigbeeClusterReply *ZigbeeClusterIdentify::identifyQuery()
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterIdentify::CommandIdentifyQuery;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
// No payload
// Put them together
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
}
ZigbeeClusterReply *ZigbeeClusterIdentify::triggerEffect(ZigbeeClusterIdentify::Effect effect, quint8 effectVariant)
{
ZigbeeNetworkRequest request = createGeneralRequest();
// Build ZCL frame
ZigbeeClusterLibrary::FrameControl frameControl;
frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific;
frameControl.manufacturerSpecific = false;
frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer;
frameControl.disableDefaultResponse = false;
// ZCL header
ZigbeeClusterLibrary::Header header;
header.frameControl = frameControl;
header.command = ZigbeeClusterIdentify::CommandTriggerEffect;
header.transactionSequenceNumber = m_transactionSequenceNumber++;
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(effect);
stream << static_cast<quint8>(effectVariant);
// Put them together
ZigbeeClusterLibrary::Frame frame;
frame.header = header;
frame.payload = payload;
request.setTxOptions(Zigbee::ZigbeeTxOptions(Zigbee::ZigbeeTxOptionAckTransmission));
request.setAsdu(ZigbeeClusterLibrary::buildFrame(frame));
ZigbeeClusterReply *zclReply = createClusterReply(request, frame);
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zclReply](){
if (!verifyNetworkError(zclReply, networkReply)) {
qCWarning(dcZigbeeClusterLibrary()) << "Failed to send request"
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZclReply(zclReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zclReply->isComplete()) {
finishZclReply(zclReply);
return;
}
});
return zclReply;
}
void ZigbeeClusterIdentify::setAttribute(const ZigbeeClusterAttribute &attribute)
{
qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(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);
}
}
void ZigbeeClusterIdentify::processDataIndication(ZigbeeClusterLibrary::Frame frame)
{
qCDebug(dcZigbeeCluster()) << "Processing cluster frame" << m_node << m_endpoint << this << frame;
// TODO: implement identify query response
// Increase the tsn for continuouse id increasing on both sides
m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame;
}

View File

@ -0,0 +1,86 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 ZIGBEECLUSTERIDENTIFY_H
#define ZIGBEECLUSTERIDENTIFY_H
#include <QObject>
#include "zcl/zigbeecluster.h"
#include "zcl/zigbeeclusterreply.h"
class ZigbeeNode;
class ZigbeeNetwork;
class ZigbeeNodeEndpoint;
class ZigbeeNetworkReply;
class ZigbeeClusterIdentify : public ZigbeeCluster
{
Q_OBJECT
friend class ZigbeeNode;
friend class ZigbeeNetwork;
public:
enum Attribute {
AttributeIdentifyTime = 0x0000
};
Q_ENUM(Attribute)
enum Command {
CommandIdentify = 0x00,
CommandIdentifyQuery = 0x01,
CommandTriggerEffect = 0x40
};
Q_ENUM(Command)
enum Effect {
EffectBlink = 0x00,
EffectBreath = 0x01,
EffectOkay = 0x02,
EffectChannelChange = 0x0b,
EffectFinishEffect = 0xfe,
EffectStopEffect = 0xff
};
Q_ENUM(Effect)
explicit ZigbeeClusterIdentify(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
ZigbeeClusterReply *identify(quint16 seconds);
ZigbeeClusterReply *identifyQuery();
ZigbeeClusterReply *triggerEffect(Effect effect, quint8 effectVariant = 0x00);
private:
void setAttribute(const ZigbeeClusterAttribute &attribute) override;
protected:
void processDataIndication(ZigbeeClusterLibrary::Frame frame) override;
};
#endif // ZIGBEECLUSTERIDENTIFY_H

View File

@ -0,0 +1,99 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 "zigbeeclusteriaszone.h"
#include "zigbeenetworkreply.h"
#include "loggingcategory.h"
#include "zigbeenetwork.h"
#include "zigbeeutils.h"
#include <QDataStream>
ZigbeeClusterIasZone::ZigbeeClusterIasZone(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, ZigbeeCluster::Direction direction, QObject *parent) :
ZigbeeCluster(network, node, endpoint, Zigbee::ClusterIdIasZone, direction, parent)
{
}
void ZigbeeClusterIasZone::setAttribute(const ZigbeeClusterAttribute &attribute)
{
qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(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);
}
}
void ZigbeeClusterIasZone::processDataIndication(ZigbeeClusterLibrary::Frame frame)
{
qCDebug(dcZigbeeCluster()) << "Processing cluster frame" << m_node << m_endpoint << this << frame;
// Increase the tsn for continuouse id increasing on both sides
m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
switch (m_direction) {
case Client:
// TODO: handle client frames
break;
case Server:
// If the client cluster sends data to a server cluster (independent which), the command was executed on the device like button pressed
if (frame.header.frameControl.direction == ZigbeeClusterLibrary::DirectionServerToClient) {
// Read the payload which is
ClientCommand command = static_cast<ClientCommand>(frame.header.command);
qCDebug(dcZigbeeCluster()) << "Command received from" << m_node << m_endpoint << this << command;
switch (command) {
case ClientCommandStatusChangedNotification: {
QDataStream stream(frame.payload);
stream.setByteOrder(QDataStream::LittleEndian);
quint16 zoneStatus = 0; quint8 extendedStatus = 0; quint8 zoneId = 0xff; quint16 delay = 0;
stream >> zoneStatus >> extendedStatus >> zoneId >> delay;
qCDebug(dcZigbeeCluster()) << "IAS zone status notification from" << m_node << m_endpoint << this
<< ZoneStatusFlags(zoneStatus) << "Extended status:" << ZigbeeUtils::convertByteToHexString(extendedStatus)
<< "Zone ID:" << ZigbeeUtils::convertByteToHexString(zoneId) << "Delay:" << delay << "[s/4]";
emit zoneStatusChanged(ZoneStatusFlags(zoneStatus), extendedStatus, zoneId, delay);
break;
}
case ClientCommandZoneEnrollRequest: {
QDataStream stream(frame.payload);
stream.setByteOrder(QDataStream::LittleEndian);
quint16 zoneTypeInt = 0; quint16 manufacturerCode = 0;
stream >> zoneTypeInt >> manufacturerCode;
ZoneType zoneType = static_cast<ZoneType>(zoneTypeInt);
qCDebug(dcZigbeeCluster()) << "IAS zone enroll request from" << m_node << m_endpoint << this
<< zoneType << "Manufacturer code:" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode);
emit zoneEnrollRequest(zoneType, manufacturerCode);
break;
}
}
}
break;
}
}

View File

@ -0,0 +1,142 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 ZIGBEECLUSTERIASZONE_H
#define ZIGBEECLUSTERIASZONE_H
#include <QObject>
#include "zcl/zigbeecluster.h"
#include "zcl/zigbeeclusterreply.h"
class ZigbeeNode;
class ZigbeeNetwork;
class ZigbeeNodeEndpoint;
class ZigbeeNetworkReply;
class ZigbeeClusterIasZone : public ZigbeeCluster
{
Q_OBJECT
friend class ZigbeeNode;
friend class ZigbeeNetwork;
public:
enum Attribute {
// Zone information attribute set
AttributeZoneState = 0x0000,
AttributeZoneType = 0x0001,
AttributeZoneStatus = 0x0002,
// Zone settings attribute set
AttributeCieAddress = 0x0010,
AttributeZoneId = 0x0011,
AttributeNumberOfZoneSensitivityLevelsSupported = 0x0012,
AttributeCurrentZoneSensitivityLevel = 0x0013
};
Q_ENUM(Attribute)
enum ZoneState {
ZoneStateNotEnrolled = 0x00,
ZoneStateEnrolled = 0x01
};
Q_ENUM(ZoneState)
enum ZoneType {
ZoneTypeStandardCIE = 0x0000,
ZoneTypeMotionSensor = 0x000d,
ZoneTypeContactSwitch = 0x0015,
ZoneTypeFireSensor = 0x0028,
ZoneTypeWaterSensor = 0x002a,
ZoneTypeCarbonMonoxideSensor = 0x002b,
ZoneTypePersonalEmergencyDevice = 0x002c,
ZoneTypeVibrationMovementSensor = 0x002d,
ZoneTypeRemoteControl = 0x010f,
ZoneTypeKeyFob = 0x0115,
ZoneTypeKeypad = 0x021d,
ZoneTypeStandardWarningDevice = 0x0225,
ZoneTypeGlassBreakSensor = 0x0226,
ZoneTypeSecurityRepater = 0x0229,
ZoneTypeInvalidZone = 0xffff
};
Q_ENUM(ZoneType)
enum ZoneStatusFlag {
ZoneStatusFlagAlarm1 = 0x0001,
ZoneStatusFlagAlarm2 = 0x0002,
ZoneStatusFlagTamper = 0x0004,
ZoneStatusFlagBattery = 0x0008,
ZoneStatusFlagSupervisionReports = 0x0010,
ZoneStatusFlagRestoreReports = 0x0020,
ZoneStatusFlagTrouble = 0x0040,
ZoneStatusFlagAcMains = 0x0080,
ZoneStatusFlagTest = 0x0100,
ZoneStatusFlagBatteryDefect = 0x0200
};
Q_ENUM(ZoneStatusFlag)
Q_DECLARE_FLAGS(ZoneStatusFlags, ZoneStatusFlag)
enum EnrollResponseCode {
EnrollResponseCodeSuccess = 0x00,
EnrollResponseCodeNotSupported = 0x01,
EnrollResponseCodeNoEnrollPermit = 0x02,
EnrollResponseCodeToManyZones = 0x03
};
Q_ENUM(EnrollResponseCode)
enum ClientCommand {
ClientCommandStatusChangedNotification = 0x00, // M
ClientCommandZoneEnrollRequest = 0x01 // M
};
Q_ENUM(ClientCommand)
enum ServerCommand {
ServerCommandEnrollResponse = 0x00, // M
ServerCommandInitNormalOperationMode = 0x01, // O
ServerCommandInitTestMode = 0x02 // O
};
Q_ENUM(ServerCommand)
explicit ZigbeeClusterIasZone(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
// TODO: write server commands
private:
void setAttribute(const ZigbeeClusterAttribute &attribute) override;
protected:
void processDataIndication(ZigbeeClusterLibrary::Frame frame) override;
signals:
void zoneStatusChanged(ZoneStatusFlags zoneStatus, quint8 extendedStatus, quint8 zoneId, quint16 delay);
void zoneEnrollRequest(ZoneType zoneType, quint16 manufacturerCode);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(ZigbeeClusterIasZone::ZoneStatusFlags)
#endif // ZIGBEECLUSTERIASZONE_H

View File

@ -218,6 +218,8 @@ void ZigbeeCluster::processDataIndication(ZigbeeClusterLibrary::Frame frame)
{
// Increase the tsn for continuouse id increasing on both sides
m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
// Warn about the unhandled cluster indication, you can override this method in cluster implementations
qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame;
}
@ -246,6 +248,9 @@ void ZigbeeCluster::processApsDataIndication(const QByteArray &asdu, const Zigbe
}
}
// Increase the tsn for continuouse id increasing on both sides
m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
return;
}
@ -261,11 +266,14 @@ void ZigbeeCluster::processApsDataIndication(const QByteArray &asdu, const Zigbe
stream >> attributeId >> type;
ZigbeeDataType dataType = ZigbeeClusterLibrary::readDataType(&stream, static_cast<Zigbee::DataType>(type));
setAttribute(ZigbeeClusterAttribute(attributeId, dataType));
// Increase the tsn for continuouse id increasing on both sides
m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
return;
}
}
// Not for a reply or not an attribute report, let the cluster process this message internally
processDataIndication(frame);
}

View File

@ -352,8 +352,7 @@ void ZigbeeNetwork::loadNetwork()
settings.setArrayIndex(n);
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(settings.value("clusterId", 0).toUInt());
ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Server);
//qCDebug(dcZigbeeNetwork()) << "Created" << cluster;
endpoint->m_inputClusters.insert(clusterId, cluster);
endpoint->addInputCluster(cluster);
}
settings.endArray(); // inputClusters
@ -362,12 +361,11 @@ void ZigbeeNetwork::loadNetwork()
settings.setArrayIndex(n);
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(settings.value("clusterId", 0).toUInt());
ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Client);
//qCDebug(dcZigbeeNetwork()) << "Created" << cluster;
endpoint->m_outputClusters.insert(clusterId, cluster);
endpoint->addOutputCluster(cluster);
}
settings.endArray(); // outputClusters
node->m_endpoints.append(endpoint);
node->m_endpoints.insert(endpoint->endpointId(), endpoint);
}
settings.endArray(); // endpoints

View File

@ -68,23 +68,17 @@ ZigbeeAddress ZigbeeNode::extendedAddress() const
QList<ZigbeeNodeEndpoint *> ZigbeeNode::endpoints() const
{
return m_endpoints;
return m_endpoints.values();
}
bool ZigbeeNode::hasEndpoint(quint8 endpointId) const
{
return getEndpoint(endpointId) != nullptr;
return m_endpoints.keys().contains(endpointId);
}
ZigbeeNodeEndpoint *ZigbeeNode::getEndpoint(quint8 endpointId) const
{
foreach (ZigbeeNodeEndpoint *endpoint, m_endpoints) {
if (endpoint->endpointId() == endpointId) {
return endpoint;
}
}
return nullptr;
return m_endpoints.value(endpointId);
}
ZigbeeNode::NodeType ZigbeeNode::nodeType() const
@ -641,7 +635,7 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
ZigbeeNodeEndpoint *endpoint = nullptr;
if (!hasEndpoint(endpointId)) {
endpoint = new ZigbeeNodeEndpoint(m_network, this, endpointId, this);
m_endpoints.append(endpoint);
m_endpoints.insert(endpoint->endpointId(), endpoint);
} else {
endpoint = getEndpoint(endpointId);
}
@ -694,7 +688,7 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
void ZigbeeNode::initBasicCluster()
{
// FIXME: check if we want to read from all endpoints the basic cluster information or only from the first
ZigbeeClusterBasic *basicCluster = m_endpoints.first()->inputCluster<ZigbeeClusterBasic>(Zigbee::ClusterIdBasic);
ZigbeeClusterBasic *basicCluster = endpoints().first()->inputCluster<ZigbeeClusterBasic>(Zigbee::ClusterIdBasic);
if (!basicCluster) {
qCWarning(dcZigbeeNode()) << "Could not find basic cluster on" << this << "Set the node to initialized anyways.";
// Set the device initialized any ways since this ist just for convinience
@ -718,7 +712,7 @@ void ZigbeeNode::readManufacturerName(ZigbeeClusterBasic *basicCluster)
bool valueOk = false;
QString manufacturerName = basicCluster->attribute(attributeId).dataType().toString(&valueOk);
if (valueOk) {
m_endpoints.first()->m_manufacturerName = manufacturerName;
endpoints().first()->m_manufacturerName = manufacturerName;
} else {
qCWarning(dcZigbeeNode()) << "Could not convert manufacturer name attribute data to string" << basicCluster->attribute(attributeId).dataType();
}
@ -742,7 +736,7 @@ void ZigbeeNode::readManufacturerName(ZigbeeClusterBasic *basicCluster)
bool valueOk = false;
QString manufacturerName = attributeStatusRecord.dataType.toString(&valueOk);
if (valueOk) {
m_endpoints.first()->m_manufacturerName = manufacturerName;
endpoints().first()->m_manufacturerName = manufacturerName;
} else {
qCWarning(dcZigbeeNode()) << "Could not convert manufacturer name attribute data to string" << attributeStatusRecord.dataType;
}
@ -766,7 +760,7 @@ void ZigbeeNode::readModelIdentifier(ZigbeeClusterBasic *basicCluster)
bool valueOk = false;
QString modelIdentifier = basicCluster->attribute(attributeId).dataType().toString(&valueOk);
if (valueOk) {
m_endpoints.first()->m_modelIdentifier= modelIdentifier;
endpoints().first()->m_modelIdentifier= modelIdentifier;
} else {
qCWarning(dcZigbeeNode()) << "Could not convert model identifier attribute data to string" << basicCluster->attribute(attributeId).dataType();
}
@ -790,7 +784,7 @@ void ZigbeeNode::readModelIdentifier(ZigbeeClusterBasic *basicCluster)
bool valueOk = false;
QString modelIdentifier = attributeStatusRecord.dataType.toString(&valueOk);
if (valueOk) {
m_endpoints.first()->m_modelIdentifier = modelIdentifier;
endpoints().first()->m_modelIdentifier = modelIdentifier;
} else {
qCWarning(dcZigbeeNode()) << "Could not convert model identifier attribute data to string" << attributeStatusRecord.dataType;
}
@ -820,7 +814,7 @@ void ZigbeeNode::readSoftwareBuildId(ZigbeeClusterBasic *basicCluster)
bool valueOk = false;
QString softwareBuildId = attributeStatusRecord.dataType.toString(&valueOk);
if (valueOk) {
m_endpoints.first()->m_softwareBuildId = softwareBuildId;
endpoints().first()->m_softwareBuildId = softwareBuildId;
} else {
qCWarning(dcZigbeeNode()) << "Could not convert software build id attribute data to string" << attributeStatusRecord.dataType;
}
@ -845,7 +839,7 @@ void ZigbeeNode::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataInd
endpoint = new ZigbeeNodeEndpoint(m_network, this, indication.sourceEndpoint, this);
endpoint->setProfile(static_cast<Zigbee::ZigbeeProfile>(indication.profileId));
// Note: the endpoint is not initializd yet, but keep it anyways
m_endpoints.append(endpoint);
m_endpoints.insert(endpoint->endpointId(), endpoint);
}
endpoint->handleZigbeeClusterLibraryIndication(indication);

View File

@ -199,7 +199,7 @@ private:
ZigbeeNetwork *m_network;
ZigbeeDeviceObject *m_deviceObject = nullptr;
QList<ZigbeeNodeEndpoint *> m_endpoints;
QHash<quint8, ZigbeeNodeEndpoint *> m_endpoints;
// Node descriptor information
QByteArray m_nodeDescriptorRawData;
@ -277,6 +277,7 @@ private:
// Init methods
int m_requestRetry = 0;
QList<quint8> m_uninitializedEndpoints;
void initNodeDescriptor();
void initPowerDescriptor();
void initEndpoints();

View File

@ -112,6 +112,11 @@ QList<ZigbeeCluster *> ZigbeeNodeEndpoint::outputClusters() const
return m_outputClusters.values();
}
ZigbeeCluster *ZigbeeNodeEndpoint::getOutputCluster(Zigbee::ClusterId clusterId) const
{
return m_outputClusters.value(clusterId);
}
bool ZigbeeNodeEndpoint::hasOutputCluster(Zigbee::ClusterId clusterId) const
{
return m_outputClusters.keys().contains(clusterId);
@ -161,18 +166,27 @@ void ZigbeeNodeEndpoint::setSoftwareBuildId(const QString &softwareBuildId)
ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, ZigbeeCluster::Direction direction)
{
switch (clusterId) {
// General
case Zigbee::ClusterIdBasic:
return new ZigbeeClusterBasic(m_network, m_node, this, direction, this);
break;
case Zigbee::ClusterIdOnOff:
return new ZigbeeClusterOnOff(m_network, m_node, this, direction, this);
break;
case Zigbee::ClusterIdIdentify:
return new ZigbeeClusterIdentify(m_network, m_node, this, direction, this);
break;
// Measurement
case Zigbee::ClusterIdTemperatureMeasurement:
return new ZigbeeClusterTemperatureMeasurement(m_network, m_node, this, direction, this);
break;
case Zigbee::ClusterIdRelativeHumidityMeasurement:
return new ZigbeeClusterRelativeHumidityMeasurement(m_network, m_node, this, direction, this);
break;
// Security
case Zigbee::ClusterIdIasZone:
return new ZigbeeClusterIasZone(m_network, m_node, this, direction, this);
break;
default:
// Return a default cluster since we have no special implementation for this cluster
return new ZigbeeCluster(m_network, m_node, this, clusterId, direction, this);
@ -182,11 +196,13 @@ ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, Zi
void ZigbeeNodeEndpoint::addInputCluster(ZigbeeCluster *cluster)
{
m_inputClusters.insert(cluster->clusterId(), cluster);
emit inputClusterAdded(cluster);
}
void ZigbeeNodeEndpoint::addOutputCluster(ZigbeeCluster *cluster)
{
m_outputClusters.insert(cluster->clusterId(), cluster);
emit outputClusterAdded(cluster);
}
void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication)
@ -203,7 +219,7 @@ void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::Apsd
if (!cluster) {
cluster = createCluster(static_cast<Zigbee::ClusterId>(indication.clusterId), ZigbeeCluster::Client);
qCWarning(dcZigbeeEndpoint()) << "Received a ZCL indication for a cluster which does not exist yet on" << m_node << this << "Creating" << cluster;
m_outputClusters.insert(cluster->clusterId(), cluster);
addOutputCluster(cluster);
}
break;
case ZigbeeClusterLibrary::DirectionServerToClient:
@ -212,7 +228,7 @@ void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::Apsd
if (!cluster) {
cluster = createCluster(static_cast<Zigbee::ClusterId>(indication.clusterId), ZigbeeCluster::Server);
qCWarning(dcZigbeeEndpoint()) << "Received a ZCL indication for a cluster which does not exist yet on" << m_node << this << "Creating" << cluster;
m_inputClusters.insert(cluster->clusterId(), cluster);
addInputCluster(cluster);
}
break;
}
@ -220,11 +236,6 @@ void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::Apsd
cluster->processApsDataIndication(indication.asdu, frame);
}
ZigbeeCluster *ZigbeeNodeEndpoint::getOutputCluster(Zigbee::ClusterId clusterId) const
{
return m_outputClusters.value(clusterId);
}
QDebug operator<<(QDebug debug, ZigbeeNodeEndpoint *endpoint)
{
debug.nospace().noquote() << "ZigbeeNodeEndpoint(" << ZigbeeUtils::convertByteToHexString(endpoint->endpointId());

View File

@ -36,11 +36,16 @@
// Import all implemented cluster types
#include "zcl/zigbeecluster.h"
#include "zcl/general/zigbeeclusterbasic.h"
#include "zcl/general/zigbeeclusteronoff.h"
#include "zcl/general/zigbeeclusteridentify.h"
#include "zcl/measurement/zigbeeclustertemperaturemeasurement.h"
#include "zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h"
#include "zcl/security/zigbeeclusteriaszone.h"
class ZigbeeNode;
class ZigbeeNetwork;
@ -82,6 +87,7 @@ public:
ZigbeeCluster *getOutputCluster(Zigbee::ClusterId clusterId) const;
bool hasOutputCluster(Zigbee::ClusterId clusterId) const;
// Convinience cast methods for getting a specific cluster object
template<typename T>
inline T* inputCluster(Zigbee::ClusterId clusterId)
{
@ -123,9 +129,6 @@ private:
void setModelIdentifier(const QString &modelIdentifier);
void setSoftwareBuildId(const QString &softwareBuildId);
// Cluster commands
//virtual void setClusterAttribute(Zigbee::ClusterId clusterId, const ZigbeeClusterAttribute &attribute = ZigbeeClusterAttribute()) = 0;
ZigbeeCluster *createCluster(Zigbee::ClusterId clusterId, ZigbeeCluster::Direction direction);
void addInputCluster(ZigbeeCluster *cluster);
@ -134,12 +137,14 @@ private:
void handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication);
signals:
void inputClusterAdded(ZigbeeCluster *cluster);
void outputClusterAdded(ZigbeeCluster *cluster);
void clusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);
void manufacturerNameChanged(const QString &manufacturerName);
void modelIdentifierChanged(const QString &modelIdentifier);
void softwareBuildIdChanged(const QString &softwareBuildId);
};
QDebug operator<<(QDebug debug, ZigbeeNodeEndpoint *endpoint);