Implement lqi updating of nodes and finishe on/off and level cluster

pull/7/head
Simon Stürz 2020-06-14 14:39:10 +02:00
parent cdd7a1a1aa
commit 8f1043ba9f
11 changed files with 125 additions and 69 deletions

View File

@ -341,8 +341,8 @@ void ZigbeeNetworkDeconz::handleZigbeeDeviceProfileIndication(const Zigbee::Apsd
return;
}
// Let the node device object handle this (ZDP)
node->deviceObject()->processApsDataIndication(indication);
// Let the node handle this indication
handleNodeIndication(node, indication);
}
void ZigbeeNetworkDeconz::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication)
@ -358,8 +358,8 @@ void ZigbeeNetworkDeconz::handleZigbeeClusterLibraryIndication(const Zigbee::Aps
// FIXME: maybe remove this node since we might have removed it but it did not respond, or we not explicitly allowed it to join.
return;
}
node->handleZigbeeClusterLibraryIndication(indication);
// Let the node handle this indication
handleNodeIndication(node, indication);
}
void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining)

View File

@ -140,17 +140,11 @@ void ZigbeeClusterLevelControl::processDataIndication(ZigbeeClusterLibrary::Fram
// Read the payload which is
Command command = static_cast<Command>(frame.header.command);
qCDebug(dcZigbeeCluster()) << "Command sent from" << m_node << m_endpoint << this << command;
switch (command) {
default:
qCWarning(dcZigbeeCluster()) << "Unhandled command sent from" << m_node << m_endpoint << this << command;
break;
}
emit commandSent(command, frame.payload);
}
break;
case Server:
qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame;
break;
}
}

View File

@ -102,6 +102,8 @@ protected:
signals:
void currentLevelChanged(quint8 level);
void commandSent(ZigbeeClusterLevelControl::Command command, const QByteArray &parameter = QByteArray());
};

View File

@ -53,6 +53,29 @@ ZigbeeClusterReply *ZigbeeClusterOnOff::commandToggle()
return executeClusterCommand(ZigbeeClusterOnOff::CommandToggle);
}
ZigbeeClusterReply *ZigbeeClusterOnOff::commandOffWithEffect(ZigbeeClusterOnOff::Effect effect, quint8 effectVariant)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(effect) << effectVariant;
return executeClusterCommand(ZigbeeClusterOnOff::CommandOffWithEffect, payload);
}
ZigbeeClusterReply *ZigbeeClusterOnOff::commandOnWithRecallGlobalScene()
{
return executeClusterCommand(ZigbeeClusterOnOff::CommandOnWithRecallGlobalScene);
}
ZigbeeClusterReply *ZigbeeClusterOnOff::commandOnWithTimedOff(bool acceptOnlyWhenOn, quint16 onTime, quint16 offWaitTime)
{
QByteArray payload;
QDataStream stream(&payload, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << static_cast<quint8>(acceptOnlyWhenOn) << onTime << offWaitTime;
return executeClusterCommand(ZigbeeClusterOnOff::CommandOnWithTimedOff, payload);
}
void ZigbeeClusterOnOff::setAttribute(const ZigbeeClusterAttribute &attribute)
{
qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast<Attribute>(attribute.id()) << attribute.dataType();

View File

@ -64,14 +64,20 @@ public:
};
Q_ENUM(Command)
enum Effect {
EffectDelayedAllOff = 0x00,
EffectDyingLight = 0x01
};
Q_ENUM(Effect)
explicit ZigbeeClusterOnOff(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr);
ZigbeeClusterReply *commandOff();
ZigbeeClusterReply *commandOn();
ZigbeeClusterReply *commandToggle();
// ZigbeeClusterReply *commandOffWithEffect();
// ZigbeeClusterReply *commandOnWithRecallGlobalScene();
// ZigbeeClusterReply *commandOnWithTimedOff();
ZigbeeClusterReply *commandOffWithEffect(Effect effect, quint8 effectVariant = 0x00);
ZigbeeClusterReply *commandOnWithRecallGlobalScene();
ZigbeeClusterReply *commandOnWithTimedOff(bool acceptOnlyWhenOn, quint16 onTime, quint16 offWaitTime);
private:
void setAttribute(const ZigbeeClusterAttribute &attribute) override;

View File

@ -224,6 +224,58 @@ ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestSimpleDescriptor(quint8 endp
return zdoReply;
}
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestBindIeeeAddress(quint8 sourceEndpointId, quint16 clusterId, const ZigbeeAddress &destinationIeeeAddress, quint8 destinationEndpointId)
{
qCDebug(dcZigbeeDeviceObject()) << "Request bind ieee address from" << m_node << "endpoint" << clusterId << "to" << destinationIeeeAddress.toString() << destinationEndpointId;
// Build APS request
ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::BindRequest);
// Generate a new transaction sequence number for this device object
quint8 transactionSequenceNumber = m_transactionSequenceNumber++;
// Build ZDO frame
QByteArray asdu;
QDataStream stream(&asdu, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << transactionSequenceNumber;
stream << m_node->extendedAddress().toUInt64();
stream << sourceEndpointId;
stream << clusterId;
stream << static_cast<quint8>(Zigbee::DestinationAddressModeIeeeAddress);
stream << destinationIeeeAddress.toUInt64();
stream << destinationEndpointId;
// Set the ZDO frame as APS request payload
request.setAsdu(asdu);
// Create the device object reply and wait for the response indication
ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber);
// Send the request, on finished read the confirm information
ZigbeeNetworkReply *networkReply = m_network->sendRequest(request);
connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){
if (!verifyNetworkError(zdoReply, networkReply)) {
qCWarning(dcZigbeeDeviceObject()) << "Failed to send request"
<< static_cast<ZigbeeDeviceProfile::ZdoCommand>(networkReply->request().clusterId())
<< m_node << networkReply->error()
<< networkReply->zigbeeApsStatus();
finishZdoReply(zdoReply);
return;
}
// The request was successfully sent to the device
// Now check if the expected indication response received already
if (zdoReply->isComplete()) {
finishZdoReply(zdoReply);
return;
}
// We received the confirmation but not yet the indication
});
return zdoReply;
}
ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestMgmtLeaveNetwork(bool rejoin, bool removeChildren)
{
qCDebug(dcZigbeeDeviceObject()) << "Request management leave network from" << m_node << "rejoin" << rejoin << "remove children" << removeChildren;

View File

@ -52,7 +52,7 @@ public:
// End device binding
// ZigbeeDeviceObjectReply *requestBindGroup(quint16 clusterId, quint16 groupAddress, quint8 destinationEndpoint);
// ZigbeeDeviceObjectReply *requestBindShortAddress();
// ZigbeeDeviceObjectReply *requestBindIeeeAddress();
ZigbeeDeviceObjectReply *requestBindIeeeAddress(quint8 sourceEndpointId, quint16 clusterId, const ZigbeeAddress &destinationIeeeAddress, quint8 destinationEndpointId);
// Management request

View File

@ -366,57 +366,6 @@ void ZigbeeNetwork::clearSettings()
m_nodeType = ZigbeeDeviceProfile::NodeTypeCoordinator;
}
void ZigbeeNetwork::saveNode(ZigbeeNode *node)
{
QSettings settings(m_settingsFileName, QSettings::IniFormat, this);
settings.beginGroup("Nodes");
// Save this node
settings.beginGroup(node->extendedAddress().toString());
settings.setValue("nwkAddress", node->shortAddress());
// Node descriptor
settings.setValue("nodeDescriptorRaw", node->nodeDescriptor().descriptorRawData);
// Power descriptor
settings.setValue("powerDescriptorFlag", node->powerDescriptor().powerDescriptoFlag);
settings.beginWriteArray("endpoints");
for (int i = 0; i < node->endpoints().count(); i++) {
ZigbeeNodeEndpoint *endpoint = node->endpoints().at(i);
settings.setArrayIndex(i);
settings.setValue("id", endpoint->endpointId());
settings.setValue("profile", endpoint->profile());
settings.setValue("deviceId", endpoint->deviceId());
settings.setValue("deviceVersion", endpoint->deviceVersion());
settings.setValue("manufacturerName", endpoint->manufacturerName());
settings.setValue("modelIdentifier", endpoint->modelIdentifier());
settings.setValue("softwareBuildId", endpoint->softwareBuildId());
settings.beginWriteArray("inputClusters");
for (int n = 0; n < endpoint->inputClusters().count(); n++) {
ZigbeeCluster *cluster = endpoint->inputClusters().at(n);
settings.setArrayIndex(n);
settings.setValue("clusterId", cluster->clusterId());
}
settings.endArray(); // inputClusters
settings.beginWriteArray("outputClusters");
for (int n = 0; n < endpoint->outputClusters().count(); n++) {
ZigbeeCluster *cluster = endpoint->outputClusters().at(n);
settings.setArrayIndex(n);
settings.setValue("clusterId", cluster->clusterId());
}
settings.endArray(); // outputClusters
}
settings.endArray(); // endpoints
settings.endGroup(); // Node ieee address
settings.endGroup(); // Nodes
}
void ZigbeeNetwork::addNode(ZigbeeNode *node)
{
qCDebug(dcZigbeeNetwork()) << "Add node" << node;
@ -483,6 +432,11 @@ bool ZigbeeNetwork::networkConfigurationAvailable() const
return m_extendedPanId != 0 && m_channel != 0 && m_coordinatorNode;
}
void ZigbeeNetwork::handleNodeIndication(ZigbeeNode *node, const Zigbee::ApsdeDataIndication indication)
{
node->handleDataIndication(indication);
}
ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest &request)
{
ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(request, this);

View File

@ -155,7 +155,6 @@ protected:
void saveNetwork();
void loadNetwork();
void clearSettings();
void saveNode(ZigbeeNode *node);
void addNode(ZigbeeNode *node);
void addUnitializedNode(ZigbeeNode *node);
@ -166,6 +165,8 @@ protected:
bool networkConfigurationAvailable() const;
void handleNodeIndication(ZigbeeNode *node, const Zigbee::ApsdeDataIndication indication);
// Network reply methods
ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest());
void setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeApsStatus zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess);

View File

@ -87,6 +87,11 @@ ZigbeeNodeEndpoint *ZigbeeNode::getEndpoint(quint8 endpointId) const
return nullptr;
}
quint8 ZigbeeNode::lqi() const
{
return m_lqi;
}
ZigbeeDeviceProfile::NodeDescriptor ZigbeeNode::nodeDescriptor() const
{
return m_nodeDescriptor;
@ -536,6 +541,24 @@ void ZigbeeNode::readSoftwareBuildId(ZigbeeClusterBasic *basicCluster)
});
}
void ZigbeeNode::handleDataIndication(const Zigbee::ApsdeDataIndication &indication)
{
if (indication.lqi != m_lqi) {
m_lqi = indication.lqi;
emit lqiChanged(m_lqi);
}
// Check if this indocation is related to any pending reply
if (indication.profileId == Zigbee::ZigbeeProfileDevice) {
deviceObject()->processApsDataIndication(indication);
return;
}
// Else let the node handle this indication
handleZigbeeClusterLibraryIndication(indication);
}
void ZigbeeNode::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication)
{
qCDebug(dcZigbeeNode()) << "Processing ZCL indication" << indication;

View File

@ -65,6 +65,8 @@ public:
bool hasEndpoint(quint8 endpointId) const;
ZigbeeNodeEndpoint *getEndpoint(quint8 endpointId) const;
quint8 lqi() const;
// Information from descriptors
ZigbeeDeviceProfile::NodeDescriptor nodeDescriptor() const;
ZigbeeDeviceProfile::MacCapabilities macCapabilities() const;
@ -114,8 +116,7 @@ private:
void readModelIdentifier(ZigbeeClusterBasic *basicCluster);
void readSoftwareBuildId(ZigbeeClusterBasic *basicCluster);
void handleDataIndication(const Zigbee::ApsdeDataIndication &indication);
signals:
void nodeInitializationFailed();