Add identify and iaszone cluster implementations
parent
9196ff83cf
commit
8105a9082b
|
|
@ -8,9 +8,11 @@ SOURCES += \
|
||||||
backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \
|
backends/deconz/interface/zigbeeinterfacedeconzreply.cpp \
|
||||||
backends/deconz/zigbeebridgecontrollerdeconz.cpp \
|
backends/deconz/zigbeebridgecontrollerdeconz.cpp \
|
||||||
backends/deconz/zigbeenetworkdeconz.cpp \
|
backends/deconz/zigbeenetworkdeconz.cpp \
|
||||||
|
zcl/general/zigbeeclusteridentify.cpp \
|
||||||
zcl/general/zigbeeclusteronoff.cpp \
|
zcl/general/zigbeeclusteronoff.cpp \
|
||||||
zcl/measurement/zigbeeclusterrelativehumiditymeasurement.cpp \
|
zcl/measurement/zigbeeclusterrelativehumiditymeasurement.cpp \
|
||||||
zcl/measurement/zigbeeclustertemperaturemeasurement.cpp \
|
zcl/measurement/zigbeeclustertemperaturemeasurement.cpp \
|
||||||
|
zcl/security/zigbeeclusteriaszone.cpp \
|
||||||
zcl/zigbeecluster.cpp \
|
zcl/zigbeecluster.cpp \
|
||||||
zcl/zigbeeclusterattribute.cpp \
|
zcl/zigbeeclusterattribute.cpp \
|
||||||
zcl/zigbeeclusterlibrary.cpp \
|
zcl/zigbeeclusterlibrary.cpp \
|
||||||
|
|
@ -52,9 +54,11 @@ HEADERS += \
|
||||||
backends/deconz/interface/zigbeeinterfacedeconzreply.h \
|
backends/deconz/interface/zigbeeinterfacedeconzreply.h \
|
||||||
backends/deconz/zigbeebridgecontrollerdeconz.h \
|
backends/deconz/zigbeebridgecontrollerdeconz.h \
|
||||||
backends/deconz/zigbeenetworkdeconz.h \
|
backends/deconz/zigbeenetworkdeconz.h \
|
||||||
|
zcl/general/zigbeeclusteridentify.h \
|
||||||
zcl/general/zigbeeclusteronoff.h \
|
zcl/general/zigbeeclusteronoff.h \
|
||||||
zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h \
|
zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h \
|
||||||
zcl/measurement/zigbeeclustertemperaturemeasurement.h \
|
zcl/measurement/zigbeeclustertemperaturemeasurement.h \
|
||||||
|
zcl/security/zigbeeclusteriaszone.h \
|
||||||
zcl/zigbeecluster.h \
|
zcl/zigbeecluster.h \
|
||||||
zcl/zigbeeclusterattribute.h \
|
zcl/zigbeeclusterattribute.h \
|
||||||
zcl/zigbeeclusterlibrary.h \
|
zcl/zigbeeclusterlibrary.h \
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -218,6 +218,8 @@ void ZigbeeCluster::processDataIndication(ZigbeeClusterLibrary::Frame frame)
|
||||||
{
|
{
|
||||||
// Increase the tsn for continuouse id increasing on both sides
|
// Increase the tsn for continuouse id increasing on both sides
|
||||||
m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
|
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;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,11 +266,14 @@ void ZigbeeCluster::processApsDataIndication(const QByteArray &asdu, const Zigbe
|
||||||
stream >> attributeId >> type;
|
stream >> attributeId >> type;
|
||||||
ZigbeeDataType dataType = ZigbeeClusterLibrary::readDataType(&stream, static_cast<Zigbee::DataType>(type));
|
ZigbeeDataType dataType = ZigbeeClusterLibrary::readDataType(&stream, static_cast<Zigbee::DataType>(type));
|
||||||
setAttribute(ZigbeeClusterAttribute(attributeId, dataType));
|
setAttribute(ZigbeeClusterAttribute(attributeId, dataType));
|
||||||
|
|
||||||
|
// Increase the tsn for continuouse id increasing on both sides
|
||||||
|
m_transactionSequenceNumber = frame.header.transactionSequenceNumber;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Not for a reply or not an attribute report, let the cluster process this message internally
|
// Not for a reply or not an attribute report, let the cluster process this message internally
|
||||||
processDataIndication(frame);
|
processDataIndication(frame);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -352,8 +352,7 @@ void ZigbeeNetwork::loadNetwork()
|
||||||
settings.setArrayIndex(n);
|
settings.setArrayIndex(n);
|
||||||
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(settings.value("clusterId", 0).toUInt());
|
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(settings.value("clusterId", 0).toUInt());
|
||||||
ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Server);
|
ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Server);
|
||||||
//qCDebug(dcZigbeeNetwork()) << "Created" << cluster;
|
endpoint->addInputCluster(cluster);
|
||||||
endpoint->m_inputClusters.insert(clusterId, cluster);
|
|
||||||
}
|
}
|
||||||
settings.endArray(); // inputClusters
|
settings.endArray(); // inputClusters
|
||||||
|
|
||||||
|
|
@ -362,12 +361,11 @@ void ZigbeeNetwork::loadNetwork()
|
||||||
settings.setArrayIndex(n);
|
settings.setArrayIndex(n);
|
||||||
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(settings.value("clusterId", 0).toUInt());
|
Zigbee::ClusterId clusterId = static_cast<Zigbee::ClusterId>(settings.value("clusterId", 0).toUInt());
|
||||||
ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Client);
|
ZigbeeCluster *cluster = endpoint->createCluster(clusterId, ZigbeeCluster::Client);
|
||||||
//qCDebug(dcZigbeeNetwork()) << "Created" << cluster;
|
endpoint->addOutputCluster(cluster);
|
||||||
endpoint->m_outputClusters.insert(clusterId, cluster);
|
|
||||||
}
|
}
|
||||||
settings.endArray(); // outputClusters
|
settings.endArray(); // outputClusters
|
||||||
|
|
||||||
node->m_endpoints.append(endpoint);
|
node->m_endpoints.insert(endpoint->endpointId(), endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.endArray(); // endpoints
|
settings.endArray(); // endpoints
|
||||||
|
|
|
||||||
|
|
@ -68,23 +68,17 @@ ZigbeeAddress ZigbeeNode::extendedAddress() const
|
||||||
|
|
||||||
QList<ZigbeeNodeEndpoint *> ZigbeeNode::endpoints() const
|
QList<ZigbeeNodeEndpoint *> ZigbeeNode::endpoints() const
|
||||||
{
|
{
|
||||||
return m_endpoints;
|
return m_endpoints.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZigbeeNode::hasEndpoint(quint8 endpointId) const
|
bool ZigbeeNode::hasEndpoint(quint8 endpointId) const
|
||||||
{
|
{
|
||||||
return getEndpoint(endpointId) != nullptr;
|
return m_endpoints.keys().contains(endpointId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZigbeeNodeEndpoint *ZigbeeNode::getEndpoint(quint8 endpointId) const
|
ZigbeeNodeEndpoint *ZigbeeNode::getEndpoint(quint8 endpointId) const
|
||||||
{
|
{
|
||||||
foreach (ZigbeeNodeEndpoint *endpoint, m_endpoints) {
|
return m_endpoints.value(endpointId);
|
||||||
if (endpoint->endpointId() == endpointId) {
|
|
||||||
return endpoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZigbeeNode::NodeType ZigbeeNode::nodeType() const
|
ZigbeeNode::NodeType ZigbeeNode::nodeType() const
|
||||||
|
|
@ -641,7 +635,7 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
|
||||||
ZigbeeNodeEndpoint *endpoint = nullptr;
|
ZigbeeNodeEndpoint *endpoint = nullptr;
|
||||||
if (!hasEndpoint(endpointId)) {
|
if (!hasEndpoint(endpointId)) {
|
||||||
endpoint = new ZigbeeNodeEndpoint(m_network, this, endpointId, this);
|
endpoint = new ZigbeeNodeEndpoint(m_network, this, endpointId, this);
|
||||||
m_endpoints.append(endpoint);
|
m_endpoints.insert(endpoint->endpointId(), endpoint);
|
||||||
} else {
|
} else {
|
||||||
endpoint = getEndpoint(endpointId);
|
endpoint = getEndpoint(endpointId);
|
||||||
}
|
}
|
||||||
|
|
@ -694,7 +688,7 @@ void ZigbeeNode::initEndpoint(quint8 endpointId)
|
||||||
void ZigbeeNode::initBasicCluster()
|
void ZigbeeNode::initBasicCluster()
|
||||||
{
|
{
|
||||||
// FIXME: check if we want to read from all endpoints the basic cluster information or only from the first
|
// 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) {
|
if (!basicCluster) {
|
||||||
qCWarning(dcZigbeeNode()) << "Could not find basic cluster on" << this << "Set the node to initialized anyways.";
|
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
|
// Set the device initialized any ways since this ist just for convinience
|
||||||
|
|
@ -718,7 +712,7 @@ void ZigbeeNode::readManufacturerName(ZigbeeClusterBasic *basicCluster)
|
||||||
bool valueOk = false;
|
bool valueOk = false;
|
||||||
QString manufacturerName = basicCluster->attribute(attributeId).dataType().toString(&valueOk);
|
QString manufacturerName = basicCluster->attribute(attributeId).dataType().toString(&valueOk);
|
||||||
if (valueOk) {
|
if (valueOk) {
|
||||||
m_endpoints.first()->m_manufacturerName = manufacturerName;
|
endpoints().first()->m_manufacturerName = manufacturerName;
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcZigbeeNode()) << "Could not convert manufacturer name attribute data to string" << basicCluster->attribute(attributeId).dataType();
|
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;
|
bool valueOk = false;
|
||||||
QString manufacturerName = attributeStatusRecord.dataType.toString(&valueOk);
|
QString manufacturerName = attributeStatusRecord.dataType.toString(&valueOk);
|
||||||
if (valueOk) {
|
if (valueOk) {
|
||||||
m_endpoints.first()->m_manufacturerName = manufacturerName;
|
endpoints().first()->m_manufacturerName = manufacturerName;
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcZigbeeNode()) << "Could not convert manufacturer name attribute data to string" << attributeStatusRecord.dataType;
|
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;
|
bool valueOk = false;
|
||||||
QString modelIdentifier = basicCluster->attribute(attributeId).dataType().toString(&valueOk);
|
QString modelIdentifier = basicCluster->attribute(attributeId).dataType().toString(&valueOk);
|
||||||
if (valueOk) {
|
if (valueOk) {
|
||||||
m_endpoints.first()->m_modelIdentifier= modelIdentifier;
|
endpoints().first()->m_modelIdentifier= modelIdentifier;
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcZigbeeNode()) << "Could not convert model identifier attribute data to string" << basicCluster->attribute(attributeId).dataType();
|
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;
|
bool valueOk = false;
|
||||||
QString modelIdentifier = attributeStatusRecord.dataType.toString(&valueOk);
|
QString modelIdentifier = attributeStatusRecord.dataType.toString(&valueOk);
|
||||||
if (valueOk) {
|
if (valueOk) {
|
||||||
m_endpoints.first()->m_modelIdentifier = modelIdentifier;
|
endpoints().first()->m_modelIdentifier = modelIdentifier;
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcZigbeeNode()) << "Could not convert model identifier attribute data to string" << attributeStatusRecord.dataType;
|
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;
|
bool valueOk = false;
|
||||||
QString softwareBuildId = attributeStatusRecord.dataType.toString(&valueOk);
|
QString softwareBuildId = attributeStatusRecord.dataType.toString(&valueOk);
|
||||||
if (valueOk) {
|
if (valueOk) {
|
||||||
m_endpoints.first()->m_softwareBuildId = softwareBuildId;
|
endpoints().first()->m_softwareBuildId = softwareBuildId;
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcZigbeeNode()) << "Could not convert software build id attribute data to string" << attributeStatusRecord.dataType;
|
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 = new ZigbeeNodeEndpoint(m_network, this, indication.sourceEndpoint, this);
|
||||||
endpoint->setProfile(static_cast<Zigbee::ZigbeeProfile>(indication.profileId));
|
endpoint->setProfile(static_cast<Zigbee::ZigbeeProfile>(indication.profileId));
|
||||||
// Note: the endpoint is not initializd yet, but keep it anyways
|
// Note: the endpoint is not initializd yet, but keep it anyways
|
||||||
m_endpoints.append(endpoint);
|
m_endpoints.insert(endpoint->endpointId(), endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint->handleZigbeeClusterLibraryIndication(indication);
|
endpoint->handleZigbeeClusterLibraryIndication(indication);
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ private:
|
||||||
|
|
||||||
ZigbeeNetwork *m_network;
|
ZigbeeNetwork *m_network;
|
||||||
ZigbeeDeviceObject *m_deviceObject = nullptr;
|
ZigbeeDeviceObject *m_deviceObject = nullptr;
|
||||||
QList<ZigbeeNodeEndpoint *> m_endpoints;
|
QHash<quint8, ZigbeeNodeEndpoint *> m_endpoints;
|
||||||
|
|
||||||
// Node descriptor information
|
// Node descriptor information
|
||||||
QByteArray m_nodeDescriptorRawData;
|
QByteArray m_nodeDescriptorRawData;
|
||||||
|
|
@ -277,6 +277,7 @@ private:
|
||||||
// Init methods
|
// Init methods
|
||||||
int m_requestRetry = 0;
|
int m_requestRetry = 0;
|
||||||
QList<quint8> m_uninitializedEndpoints;
|
QList<quint8> m_uninitializedEndpoints;
|
||||||
|
|
||||||
void initNodeDescriptor();
|
void initNodeDescriptor();
|
||||||
void initPowerDescriptor();
|
void initPowerDescriptor();
|
||||||
void initEndpoints();
|
void initEndpoints();
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,11 @@ QList<ZigbeeCluster *> ZigbeeNodeEndpoint::outputClusters() const
|
||||||
return m_outputClusters.values();
|
return m_outputClusters.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZigbeeCluster *ZigbeeNodeEndpoint::getOutputCluster(Zigbee::ClusterId clusterId) const
|
||||||
|
{
|
||||||
|
return m_outputClusters.value(clusterId);
|
||||||
|
}
|
||||||
|
|
||||||
bool ZigbeeNodeEndpoint::hasOutputCluster(Zigbee::ClusterId clusterId) const
|
bool ZigbeeNodeEndpoint::hasOutputCluster(Zigbee::ClusterId clusterId) const
|
||||||
{
|
{
|
||||||
return m_outputClusters.keys().contains(clusterId);
|
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)
|
ZigbeeCluster *ZigbeeNodeEndpoint::createCluster(Zigbee::ClusterId clusterId, ZigbeeCluster::Direction direction)
|
||||||
{
|
{
|
||||||
switch (clusterId) {
|
switch (clusterId) {
|
||||||
|
// General
|
||||||
case Zigbee::ClusterIdBasic:
|
case Zigbee::ClusterIdBasic:
|
||||||
return new ZigbeeClusterBasic(m_network, m_node, this, direction, this);
|
return new ZigbeeClusterBasic(m_network, m_node, this, direction, this);
|
||||||
break;
|
break;
|
||||||
case Zigbee::ClusterIdOnOff:
|
case Zigbee::ClusterIdOnOff:
|
||||||
return new ZigbeeClusterOnOff(m_network, m_node, this, direction, this);
|
return new ZigbeeClusterOnOff(m_network, m_node, this, direction, this);
|
||||||
break;
|
break;
|
||||||
|
case Zigbee::ClusterIdIdentify:
|
||||||
|
return new ZigbeeClusterIdentify(m_network, m_node, this, direction, this);
|
||||||
|
break;
|
||||||
|
// Measurement
|
||||||
case Zigbee::ClusterIdTemperatureMeasurement:
|
case Zigbee::ClusterIdTemperatureMeasurement:
|
||||||
return new ZigbeeClusterTemperatureMeasurement(m_network, m_node, this, direction, this);
|
return new ZigbeeClusterTemperatureMeasurement(m_network, m_node, this, direction, this);
|
||||||
break;
|
break;
|
||||||
case Zigbee::ClusterIdRelativeHumidityMeasurement:
|
case Zigbee::ClusterIdRelativeHumidityMeasurement:
|
||||||
return new ZigbeeClusterRelativeHumidityMeasurement(m_network, m_node, this, direction, this);
|
return new ZigbeeClusterRelativeHumidityMeasurement(m_network, m_node, this, direction, this);
|
||||||
break;
|
break;
|
||||||
|
// Security
|
||||||
|
case Zigbee::ClusterIdIasZone:
|
||||||
|
return new ZigbeeClusterIasZone(m_network, m_node, this, direction, this);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// Return a default cluster since we have no special implementation for this cluster
|
// Return a default cluster since we have no special implementation for this cluster
|
||||||
return new ZigbeeCluster(m_network, m_node, this, clusterId, direction, this);
|
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)
|
void ZigbeeNodeEndpoint::addInputCluster(ZigbeeCluster *cluster)
|
||||||
{
|
{
|
||||||
m_inputClusters.insert(cluster->clusterId(), cluster);
|
m_inputClusters.insert(cluster->clusterId(), cluster);
|
||||||
|
emit inputClusterAdded(cluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigbeeNodeEndpoint::addOutputCluster(ZigbeeCluster *cluster)
|
void ZigbeeNodeEndpoint::addOutputCluster(ZigbeeCluster *cluster)
|
||||||
{
|
{
|
||||||
m_outputClusters.insert(cluster->clusterId(), cluster);
|
m_outputClusters.insert(cluster->clusterId(), cluster);
|
||||||
|
emit outputClusterAdded(cluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication)
|
void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication)
|
||||||
|
|
@ -203,7 +219,7 @@ void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::Apsd
|
||||||
if (!cluster) {
|
if (!cluster) {
|
||||||
cluster = createCluster(static_cast<Zigbee::ClusterId>(indication.clusterId), ZigbeeCluster::Client);
|
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;
|
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;
|
break;
|
||||||
case ZigbeeClusterLibrary::DirectionServerToClient:
|
case ZigbeeClusterLibrary::DirectionServerToClient:
|
||||||
|
|
@ -212,7 +228,7 @@ void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::Apsd
|
||||||
if (!cluster) {
|
if (!cluster) {
|
||||||
cluster = createCluster(static_cast<Zigbee::ClusterId>(indication.clusterId), ZigbeeCluster::Server);
|
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;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -220,11 +236,6 @@ void ZigbeeNodeEndpoint::handleZigbeeClusterLibraryIndication(const Zigbee::Apsd
|
||||||
cluster->processApsDataIndication(indication.asdu, frame);
|
cluster->processApsDataIndication(indication.asdu, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZigbeeCluster *ZigbeeNodeEndpoint::getOutputCluster(Zigbee::ClusterId clusterId) const
|
|
||||||
{
|
|
||||||
return m_outputClusters.value(clusterId);
|
|
||||||
}
|
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, ZigbeeNodeEndpoint *endpoint)
|
QDebug operator<<(QDebug debug, ZigbeeNodeEndpoint *endpoint)
|
||||||
{
|
{
|
||||||
debug.nospace().noquote() << "ZigbeeNodeEndpoint(" << ZigbeeUtils::convertByteToHexString(endpoint->endpointId());
|
debug.nospace().noquote() << "ZigbeeNodeEndpoint(" << ZigbeeUtils::convertByteToHexString(endpoint->endpointId());
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,16 @@
|
||||||
|
|
||||||
// Import all implemented cluster types
|
// Import all implemented cluster types
|
||||||
#include "zcl/zigbeecluster.h"
|
#include "zcl/zigbeecluster.h"
|
||||||
|
|
||||||
#include "zcl/general/zigbeeclusterbasic.h"
|
#include "zcl/general/zigbeeclusterbasic.h"
|
||||||
#include "zcl/general/zigbeeclusteronoff.h"
|
#include "zcl/general/zigbeeclusteronoff.h"
|
||||||
|
#include "zcl/general/zigbeeclusteridentify.h"
|
||||||
|
|
||||||
#include "zcl/measurement/zigbeeclustertemperaturemeasurement.h"
|
#include "zcl/measurement/zigbeeclustertemperaturemeasurement.h"
|
||||||
#include "zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h"
|
#include "zcl/measurement/zigbeeclusterrelativehumiditymeasurement.h"
|
||||||
|
|
||||||
|
#include "zcl/security/zigbeeclusteriaszone.h"
|
||||||
|
|
||||||
class ZigbeeNode;
|
class ZigbeeNode;
|
||||||
class ZigbeeNetwork;
|
class ZigbeeNetwork;
|
||||||
|
|
||||||
|
|
@ -82,6 +87,7 @@ public:
|
||||||
ZigbeeCluster *getOutputCluster(Zigbee::ClusterId clusterId) const;
|
ZigbeeCluster *getOutputCluster(Zigbee::ClusterId clusterId) const;
|
||||||
bool hasOutputCluster(Zigbee::ClusterId clusterId) const;
|
bool hasOutputCluster(Zigbee::ClusterId clusterId) const;
|
||||||
|
|
||||||
|
// Convinience cast methods for getting a specific cluster object
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T* inputCluster(Zigbee::ClusterId clusterId)
|
inline T* inputCluster(Zigbee::ClusterId clusterId)
|
||||||
{
|
{
|
||||||
|
|
@ -123,9 +129,6 @@ private:
|
||||||
void setModelIdentifier(const QString &modelIdentifier);
|
void setModelIdentifier(const QString &modelIdentifier);
|
||||||
void setSoftwareBuildId(const QString &softwareBuildId);
|
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);
|
ZigbeeCluster *createCluster(Zigbee::ClusterId clusterId, ZigbeeCluster::Direction direction);
|
||||||
|
|
||||||
void addInputCluster(ZigbeeCluster *cluster);
|
void addInputCluster(ZigbeeCluster *cluster);
|
||||||
|
|
@ -134,12 +137,14 @@ private:
|
||||||
void handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication);
|
void handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void inputClusterAdded(ZigbeeCluster *cluster);
|
||||||
|
void outputClusterAdded(ZigbeeCluster *cluster);
|
||||||
|
|
||||||
void clusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);
|
void clusterAttributeChanged(ZigbeeCluster *cluster, const ZigbeeClusterAttribute &attribute);
|
||||||
|
|
||||||
void manufacturerNameChanged(const QString &manufacturerName);
|
void manufacturerNameChanged(const QString &manufacturerName);
|
||||||
void modelIdentifierChanged(const QString &modelIdentifier);
|
void modelIdentifierChanged(const QString &modelIdentifier);
|
||||||
void softwareBuildIdChanged(const QString &softwareBuildId);
|
void softwareBuildIdChanged(const QString &softwareBuildId);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, ZigbeeNodeEndpoint *endpoint);
|
QDebug operator<<(QDebug debug, ZigbeeNodeEndpoint *endpoint);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue