Add deCONZ backend and implement basic uart communication and begin network initialization
This commit is contained in:
parent
43fb5bef92
commit
95caaab5ce
BIN
docs/deCONZ-BHB-en.pdf
Normal file
BIN
docs/deCONZ-BHB-en.pdf
Normal file
Binary file not shown.
112
libnymea-zigbee/deconz/interface/deconz.h
Normal file
112
libnymea-zigbee/deconz/interface/deconz.h
Normal file
@ -0,0 +1,112 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 DECONZ_H
|
||||
#define DECONZ_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Deconz
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
enum StatusCode {
|
||||
StatusCodeSuccess = 0x00,
|
||||
StatusCodeFailure = 0x01,
|
||||
StatusCodeBusy = 0x02,
|
||||
StatusCodeTimeout = 0x03,
|
||||
StatusCodeUnsupported = 0x04,
|
||||
StatusCodeError = 0x05,
|
||||
StatusCodeNoNetwork = 0x06,
|
||||
StatusCodeInvalidValue = 0x07
|
||||
};
|
||||
Q_ENUM(StatusCode)
|
||||
|
||||
enum NetworkState {
|
||||
NetworkStateOffline = 0x00,
|
||||
NetworkStateJoining = 0x01,
|
||||
NetworkStateConnected = 0x02,
|
||||
NetworkStateLeaving = 0x03
|
||||
};
|
||||
Q_ENUM(NetworkState)
|
||||
|
||||
enum Command {
|
||||
CommandDeviceState = 0x07,
|
||||
CommandChangeNetworkState = 0x08,
|
||||
CommandReadParameter = 0x0A,
|
||||
CommandWriteParameter = 0x0B,
|
||||
CommandDeviceStateChanged = 0x0E,
|
||||
CommandVersion = 0x0D,
|
||||
CommandApsDataRequest = 0x12,
|
||||
CommandApsDataConfirm = 0x04,
|
||||
CommandApsDataIndication = 0x17
|
||||
};
|
||||
Q_ENUM(Command)
|
||||
|
||||
enum Parameter {
|
||||
ParameterMacAddress = 0x01, // R
|
||||
ParameterPanId = 0x05, // R
|
||||
ParameterNetworkAddress = 0x07, // R
|
||||
ParameterNetworkExtendedPanId = 0x08, // R
|
||||
ParameterNodeType = 0x09, //RW
|
||||
ParameterChannelMask = 0x0A, // RW
|
||||
ParameterApsExtendedPanId = 0x0B, //RW
|
||||
ParameterTrustCenterAddress = 0x0E, // RW
|
||||
ParameterSecurityMode = 0x10, // RW
|
||||
ParameterNetworkKey = 0x18, //W
|
||||
ParameterCurrentChannel = 0x1c, // R
|
||||
ParameterPermitJoin = 0x21, // RW
|
||||
ParameterProtocolVersion = 0x22, // R
|
||||
ParameterNetworkUpdateId = 0x24, // RW
|
||||
ParameterWatchdogTtl = 0x26 // RW since protocol version 0x0108
|
||||
};
|
||||
Q_ENUM(Parameter)
|
||||
|
||||
enum NodeType {
|
||||
NodeTypeRouter = 0x00,
|
||||
NodeTypeCoordinator = 0x01
|
||||
};
|
||||
Q_ENUM(NodeType)
|
||||
|
||||
enum SecurityMode {
|
||||
SecurityModeNoSecurity = 0x00,
|
||||
SecurityModePreconfiguredNetworkKey = 0x01,
|
||||
SecurityModeNetworkKeyFromTrustCenter = 0x02,
|
||||
SecurityModeNoMasterButTrustCenterKey = 0x03
|
||||
};
|
||||
Q_ENUM(SecurityMode)
|
||||
|
||||
enum Platform {
|
||||
PlatformConbeeRaspbee = 0x05,
|
||||
PlatformConbeeII = 0x07
|
||||
};
|
||||
Q_ENUM(Platform)
|
||||
|
||||
};
|
||||
|
||||
#endif // DECONZ_H
|
||||
272
libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.cpp
Normal file
272
libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 "zigbeeinterfacedeconz.h"
|
||||
#include "zigbee.h"
|
||||
#include "zigbeeutils.h"
|
||||
#include "loggingcategory.h"
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
// SLIP: https://tools.ietf.org/html/rfc1055
|
||||
|
||||
ZigbeeInterfaceDeconz::ZigbeeInterfaceDeconz(QObject *parent) : QObject(parent)
|
||||
{
|
||||
m_reconnectTimer = new QTimer(this);
|
||||
m_reconnectTimer->setSingleShot(true);
|
||||
m_reconnectTimer->setInterval(2000);
|
||||
|
||||
connect(m_reconnectTimer, &QTimer::timeout, this, &ZigbeeInterfaceDeconz::onReconnectTimeout);
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconz::~ZigbeeInterfaceDeconz()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
quint16 ZigbeeInterfaceDeconz::calculateCrc(const QByteArray &data)
|
||||
{
|
||||
quint16 crc = 0;
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
crc += static_cast<quint8>(data.at(i));
|
||||
}
|
||||
quint8 crc0 = (~crc + 1) & 0xFF;
|
||||
quint8 crc1 = ((~crc + 1) >> 8) & 0xFF;
|
||||
return (static_cast<quint16>(crc1 << 8) | static_cast<quint16>(crc0));
|
||||
}
|
||||
|
||||
QByteArray ZigbeeInterfaceDeconz::unescapeData(const QByteArray &data)
|
||||
{
|
||||
QByteArray deserializedData;
|
||||
// Parse serial data and built InterfaceMessage
|
||||
bool escaped = false;
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
quint8 byte = static_cast<quint8>(data.at(i));
|
||||
|
||||
if (escaped) {
|
||||
if (byte == ProtocolByteTransposedEnd) {
|
||||
deserializedData.append(static_cast<char>(ProtocolByteEnd));
|
||||
} else if (byte == ProtocolByteTransposedEsc) {
|
||||
deserializedData.append(static_cast<char>(ProtocolByteEsc));
|
||||
} else {
|
||||
qCWarning(dcZigbeeInterfaceTraffic()) << "Error while deserialing data. Escape character received but the escaped character was not recognized.";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If escape byte, the next byte has to be a modified byte
|
||||
if (byte == ProtocolByteEsc) {
|
||||
escaped = true;
|
||||
} else {
|
||||
deserializedData.append(static_cast<char>(byte));
|
||||
}
|
||||
}
|
||||
|
||||
return deserializedData;
|
||||
}
|
||||
|
||||
QByteArray ZigbeeInterfaceDeconz::escapeData(const QByteArray &data)
|
||||
{
|
||||
QByteArray serializedData;
|
||||
QDataStream stream(&serializedData, QIODevice::WriteOnly);
|
||||
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
quint8 byte = static_cast<quint8>(data.at(i));
|
||||
switch (byte) {
|
||||
case ProtocolByteEnd:
|
||||
stream << static_cast<quint8>(ProtocolByteEsc);
|
||||
stream << static_cast<quint8>(ProtocolByteTransposedEnd);
|
||||
break;
|
||||
case ProtocolByteEsc:
|
||||
stream << static_cast<quint8>(ProtocolByteEsc);
|
||||
stream << static_cast<quint8>(ProtocolByteTransposedEsc);
|
||||
break;
|
||||
default:
|
||||
stream << byte;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return serializedData;
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceDeconz::setAvailable(bool available)
|
||||
{
|
||||
if (m_available == available)
|
||||
return;
|
||||
|
||||
m_available = available;
|
||||
emit availableChanged(m_available);
|
||||
|
||||
// Clear the data buffer in any case
|
||||
m_dataBuffer.clear();
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceDeconz::onReconnectTimeout()
|
||||
{
|
||||
if (m_serialPort && !m_serialPort->isOpen()) {
|
||||
if (!m_serialPort->open(QSerialPort::ReadWrite)) {
|
||||
setAvailable(false);
|
||||
m_reconnectTimer->start();
|
||||
} else {
|
||||
qCDebug(dcZigbeeInterface()) << "Interface reconnected successfully on" << m_serialPort->portName() << m_serialPort->baudRate();
|
||||
m_serialPort->clear();
|
||||
setAvailable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceDeconz::onReadyRead()
|
||||
{
|
||||
QByteArray data = m_serialPort->readAll();
|
||||
// Read each byte until we get END byte, then unescape the package
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
quint8 byte = static_cast<quint8>(data.at(i));
|
||||
if (byte == ProtocolByteEnd) {
|
||||
// If there is no data...continue since it might be a starting END byte
|
||||
if (m_dataBuffer.isEmpty())
|
||||
continue;
|
||||
|
||||
qCDebug(dcZigbeeInterfaceTraffic()) << "<--" << ZigbeeUtils::convertByteArrayToHexString(m_dataBuffer);
|
||||
QByteArray frame = unescapeData(m_dataBuffer);
|
||||
if (frame.isNull()) {
|
||||
qCWarning(dcZigbeeInterface()) << "Received inconsistant message. Ignoring data" << ZigbeeUtils::convertByteArrayToHexString(m_dataBuffer);
|
||||
} else {
|
||||
QByteArray package = frame.left(frame.length() - 2);
|
||||
QByteArray checksumBytes = frame.right(2);
|
||||
QDataStream stream(&checksumBytes, QIODevice::ReadOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 receivedChecksum = 0;
|
||||
stream >> receivedChecksum;
|
||||
quint16 calculatedChecksum = calculateCrc(package);
|
||||
if (receivedChecksum != calculatedChecksum) {
|
||||
qCWarning(dcZigbeeInterfaceTraffic()) << "Checksum verification failed for frame" << ZigbeeUtils::convertByteArrayToHexString(m_dataBuffer) << receivedChecksum << "!=" << calculatedChecksum;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Checksum verified, we got valid data
|
||||
emit packageReceived(package);
|
||||
}
|
||||
m_dataBuffer.clear();
|
||||
} else {
|
||||
m_dataBuffer.append(data.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceDeconz::onError(const QSerialPort::SerialPortError &error)
|
||||
{
|
||||
if (error != QSerialPort::NoError && m_serialPort->isOpen()) {
|
||||
qCWarning(dcZigbeeInterface()) << "Serial port error:" << error << m_serialPort->errorString();
|
||||
m_reconnectTimer->start();
|
||||
m_serialPort->close();
|
||||
setAvailable(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceDeconz::sendPackage(const QByteArray &package)
|
||||
{
|
||||
if (!m_available) {
|
||||
qCWarning(dcZigbeeInterface()) << "Can not send data. The interface is not available";
|
||||
return;
|
||||
}
|
||||
|
||||
// Build the frame and escape the package data and crc
|
||||
quint16 checksum = calculateCrc(package);
|
||||
|
||||
QByteArray frame = package;
|
||||
QDataStream frameStream(&frame, QIODevice::WriteOnly | QIODevice::Append);
|
||||
frameStream.setByteOrder(QDataStream::LittleEndian);
|
||||
frameStream << checksum;
|
||||
|
||||
// Escape data according to SLIP for transfere
|
||||
QByteArray serializedData = escapeData(frame);
|
||||
|
||||
// Build transport data
|
||||
QByteArray data;
|
||||
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
stream << static_cast<quint8>(ProtocolByteEnd); // Start with SLIP END character
|
||||
for (int i = 0; i < serializedData.length(); i++)
|
||||
stream << static_cast<quint8>(serializedData.at(i));
|
||||
|
||||
stream << static_cast<quint8>(ProtocolByteEnd); // End with SLIP END character
|
||||
|
||||
// Send the data
|
||||
qCDebug(dcZigbeeInterfaceTraffic()) << "-->" << ZigbeeUtils::convertByteArrayToHexString(data);
|
||||
if (m_serialPort->write(data) < 0) {
|
||||
qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteArrayToHexString(data);
|
||||
}
|
||||
|
||||
m_serialPort->flush();
|
||||
}
|
||||
|
||||
bool ZigbeeInterfaceDeconz::enable(const QString &serialPort, qint32 baudrate)
|
||||
{
|
||||
if (m_serialPort) {
|
||||
delete m_serialPort;
|
||||
m_serialPort = nullptr;
|
||||
}
|
||||
|
||||
setAvailable(false);
|
||||
|
||||
m_serialPort = new QSerialPort(serialPort, this);
|
||||
m_serialPort->setBaudRate(baudrate);
|
||||
m_serialPort->setDataBits(QSerialPort::Data8);
|
||||
m_serialPort->setStopBits(QSerialPort::OneStop);
|
||||
m_serialPort->setParity(QSerialPort::NoParity);
|
||||
m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
|
||||
|
||||
connect(m_serialPort, &QSerialPort::readyRead, this, &ZigbeeInterfaceDeconz::onReadyRead);
|
||||
connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onError(QSerialPort::SerialPortError)));
|
||||
|
||||
if (!m_serialPort->open(QSerialPort::ReadWrite)) {
|
||||
qCWarning(dcZigbeeInterface()) << "Could not open serial port" << serialPort << baudrate;
|
||||
m_reconnectTimer->start();
|
||||
return false;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeInterface()) << "Interface enabled successfully on" << serialPort << baudrate;
|
||||
setAvailable(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZigbeeInterfaceDeconz::disable()
|
||||
{
|
||||
if (!m_serialPort)
|
||||
return;
|
||||
|
||||
if (m_serialPort->isOpen())
|
||||
m_serialPort->close();
|
||||
|
||||
delete m_serialPort;
|
||||
m_serialPort = nullptr;
|
||||
setAvailable(false);
|
||||
qCDebug(dcZigbeeInterface()) << "Interface disabled";
|
||||
}
|
||||
82
libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.h
Normal file
82
libnymea-zigbee/deconz/interface/zigbeeinterfacedeconz.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 ZIGBEEINTERFACEDECONZ_H
|
||||
#define ZIGBEEINTERFACEDECONZ_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QSerialPort>
|
||||
|
||||
class ZigbeeInterfaceDeconz : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ProtocolByte {
|
||||
ProtocolByteEnd = 0xC0,
|
||||
ProtocolByteEsc = 0xDB,
|
||||
ProtocolByteTransposedEnd = 0xDC,
|
||||
ProtocolByteTransposedEsc = 0xDD
|
||||
};
|
||||
Q_ENUM(ProtocolByte)
|
||||
|
||||
explicit ZigbeeInterfaceDeconz(QObject *parent = nullptr);
|
||||
~ZigbeeInterfaceDeconz();
|
||||
|
||||
bool available() const;
|
||||
QString serialPort() const;
|
||||
|
||||
private:
|
||||
QTimer *m_reconnectTimer = nullptr;
|
||||
QSerialPort *m_serialPort = nullptr;
|
||||
bool m_available = false;
|
||||
QByteArray m_dataBuffer;
|
||||
|
||||
quint16 calculateCrc(const QByteArray &data);
|
||||
QByteArray unescapeData(const QByteArray &data);
|
||||
QByteArray escapeData(const QByteArray &data);
|
||||
|
||||
void setAvailable(bool available);
|
||||
|
||||
signals:
|
||||
void availableChanged(bool available);
|
||||
void packageReceived(const QByteArray &package);
|
||||
|
||||
private slots:
|
||||
void onReconnectTimeout();
|
||||
void onReadyRead();
|
||||
void onError(const QSerialPort::SerialPortError &error);
|
||||
|
||||
public slots:
|
||||
void sendPackage(const QByteArray &package);
|
||||
|
||||
bool enable(const QString &serialPort = "/dev/ttyS0", qint32 baudrate = 115200);
|
||||
void disable();
|
||||
|
||||
};
|
||||
|
||||
#endif // ZIGBEEINTERFACEDECONZ_H
|
||||
@ -0,0 +1,56 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 "zigbeeinterfacedeconzreply.h"
|
||||
|
||||
Deconz::Command ZigbeeInterfaceDeconzReply::command() const
|
||||
{
|
||||
return m_command;
|
||||
}
|
||||
|
||||
quint8 ZigbeeInterfaceDeconzReply::sequenceNumber() const
|
||||
{
|
||||
return m_sequenceNumber;
|
||||
}
|
||||
|
||||
QByteArray ZigbeeInterfaceDeconzReply::responseData() const
|
||||
{
|
||||
return m_responseData;
|
||||
}
|
||||
|
||||
Deconz::StatusCode ZigbeeInterfaceDeconzReply::statusCode() const
|
||||
{
|
||||
return m_statusCode;
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconzReply::ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_command(command),
|
||||
m_sequenceNumber(sequenceNumber)
|
||||
{
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 ZIGBEEINTERFACEDECONZREPLY_H
|
||||
#define ZIGBEEINTERFACEDECONZREPLY_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "deconz.h"
|
||||
|
||||
class ZigbeeInterfaceDeconzReply : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ZigbeeBridgeControllerDeconz;
|
||||
|
||||
public:
|
||||
// Request content
|
||||
Deconz::Command command() const;
|
||||
quint8 sequenceNumber() const;
|
||||
QByteArray responseData() const;
|
||||
|
||||
// Response content
|
||||
Deconz::StatusCode statusCode() const;
|
||||
|
||||
private:
|
||||
explicit ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent = nullptr);
|
||||
|
||||
// Request content
|
||||
Deconz::Command m_command;
|
||||
quint8 m_sequenceNumber = 0;
|
||||
|
||||
// Response content
|
||||
Deconz::StatusCode m_statusCode = Deconz::StatusCodeError;
|
||||
QByteArray m_responseData;
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
};
|
||||
|
||||
#endif // ZIGBEEINTERFACEDECONZREPLY_H
|
||||
589
libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp
Normal file
589
libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.cpp
Normal file
@ -0,0 +1,589 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 "zigbeebridgecontrollerdeconz.h"
|
||||
#include "loggingcategory.h"
|
||||
#include "zigbeeutils.h"
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
ZigbeeBridgeControllerDeconz::ZigbeeBridgeControllerDeconz(QObject *parent) :
|
||||
ZigbeeBridgeController(parent)
|
||||
{
|
||||
m_interface = new ZigbeeInterfaceDeconz(this);
|
||||
connect(m_interface, &ZigbeeInterfaceDeconz::availableChanged, this, &ZigbeeBridgeControllerDeconz::onInterfaceAvailableChanged);
|
||||
connect(m_interface, &ZigbeeInterfaceDeconz::packageReceived, this, &ZigbeeBridgeControllerDeconz::onInterfacePackageReceived);
|
||||
|
||||
m_watchdogTimer = new QTimer(this);
|
||||
m_watchdogTimer->setSingleShot(false);
|
||||
m_watchdogTimer->setInterval(m_watchdogResetTimout * 1000); // Set the watchdog to 85 seconds, reset every 60 s
|
||||
connect(m_watchdogTimer, &QTimer::timeout, this, &ZigbeeBridgeControllerDeconz::onWatchdogTimerTimeout);
|
||||
}
|
||||
|
||||
ZigbeeBridgeControllerDeconz::~ZigbeeBridgeControllerDeconz()
|
||||
{
|
||||
qCDebug(dcZigbeeController()) << "Destroy controller";
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestVersion()
|
||||
{
|
||||
quint8 sequenceNumber = generateSequenceNumber();
|
||||
qCDebug(dcZigbeeController()) << "Request version. SQN:" << sequenceNumber;
|
||||
|
||||
QByteArray message;
|
||||
QDataStream stream(&message, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
stream << static_cast<quint8>(Deconz::CommandVersion);
|
||||
stream << static_cast<quint8>(sequenceNumber);
|
||||
stream << static_cast<quint8>(0); // Reserverd
|
||||
stream << static_cast<quint16>(5); // Frame length
|
||||
|
||||
ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(Deconz::CommandVersion, sequenceNumber, this);
|
||||
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater);
|
||||
m_pendingReplies.insert(sequenceNumber, reply);
|
||||
|
||||
m_interface->sendPackage(message);
|
||||
return reply;
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestDeviceState()
|
||||
{
|
||||
quint8 sequenceNumber = generateSequenceNumber();
|
||||
qCDebug(dcZigbeeController()) << "Request device state. SQN:" << sequenceNumber;
|
||||
|
||||
QByteArray message;
|
||||
QDataStream stream(&message, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
stream << static_cast<quint8>(Deconz::CommandDeviceState);
|
||||
stream << static_cast<quint8>(sequenceNumber);
|
||||
stream << static_cast<quint8>(0); // Reserverd
|
||||
stream << static_cast<quint16>(8); // Frame length
|
||||
stream << static_cast<quint8>(0); // Reserverd
|
||||
stream << static_cast<quint8>(0); // Reserverd
|
||||
stream << static_cast<quint8>(0); // Reserverd
|
||||
|
||||
ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(Deconz::CommandDeviceState, sequenceNumber, this);
|
||||
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater);
|
||||
m_pendingReplies.insert(sequenceNumber, reply);
|
||||
|
||||
m_interface->sendPackage(message);
|
||||
|
||||
return createReply(Deconz::CommandDeviceState, sequenceNumber, this);
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestReadParameter(Deconz::Parameter parameter)
|
||||
{
|
||||
quint8 sequenceNumber = generateSequenceNumber();
|
||||
qCDebug(dcZigbeeController()) << "Request read parameter. SQN:" << sequenceNumber << parameter;
|
||||
|
||||
QByteArray message;
|
||||
QDataStream stream(&message, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
stream << static_cast<quint8>(Deconz::CommandReadParameter);
|
||||
stream << static_cast<quint8>(sequenceNumber);
|
||||
stream << static_cast<quint8>(0); // Reserverd
|
||||
stream << static_cast<quint16>(8); // Frame length 7 + 1 payload
|
||||
stream << static_cast<quint16>(1); // Payload length
|
||||
stream << static_cast<quint8>(parameter);
|
||||
|
||||
m_interface->sendPackage(message);
|
||||
|
||||
return createReply(Deconz::CommandReadParameter, sequenceNumber, this);
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestWriteParameter(Deconz::Parameter parameter, const QByteArray &data)
|
||||
{
|
||||
quint8 sequenceNumber = generateSequenceNumber();
|
||||
qCDebug(dcZigbeeController()) << "Request write parameter. SQN:" << sequenceNumber << parameter << ZigbeeUtils::convertByteArrayToHexString(data);
|
||||
|
||||
QByteArray message;
|
||||
QDataStream stream(&message, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
stream << static_cast<quint8>(Deconz::CommandWriteParameter);
|
||||
stream << static_cast<quint8>(sequenceNumber);
|
||||
stream << static_cast<quint8>(0); // Reserverd
|
||||
stream << static_cast<quint16>(7 + 1 + data.length()); // Frame length 7 + 1 parameter + payload length
|
||||
stream << static_cast<quint16>(1 + data.length()); // 1 parameter + payload length
|
||||
stream << static_cast<quint8>(parameter);
|
||||
for (int i = 0; i < data.length(); i++) {
|
||||
stream << static_cast<quint8>(data.at(i));
|
||||
}
|
||||
|
||||
m_interface->sendPackage(message);
|
||||
|
||||
return createReply(Deconz::CommandWriteParameter, sequenceNumber, this);
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestChangeNetworkState(Deconz::NetworkState networkState)
|
||||
{
|
||||
quint8 sequenceNumber = generateSequenceNumber();
|
||||
qCDebug(dcZigbeeController()) << "Request change network state. SQN:" << sequenceNumber << networkState;
|
||||
|
||||
QByteArray message;
|
||||
QDataStream stream(&message, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
stream << static_cast<quint8>(Deconz::CommandChangeNetworkState);
|
||||
stream << static_cast<quint8>(sequenceNumber);
|
||||
stream << static_cast<quint8>(0); // Reserverd
|
||||
stream << static_cast<quint16>(6); // Frame length
|
||||
stream << static_cast<quint8>(networkState);
|
||||
|
||||
m_interface->sendPackage(message);
|
||||
|
||||
return createReply(Deconz::CommandChangeNetworkState, sequenceNumber, this);
|
||||
}
|
||||
|
||||
|
||||
quint8 ZigbeeBridgeControllerDeconz::generateSequenceNumber()
|
||||
{
|
||||
return m_sequenceNumber++;
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent)
|
||||
{
|
||||
// Create the reply
|
||||
ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(command, sequenceNumber, parent);
|
||||
|
||||
// Auto delete the object on finished
|
||||
connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater);
|
||||
|
||||
// Add it to the pending list
|
||||
m_pendingReplies.insert(sequenceNumber, reply);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters()
|
||||
{
|
||||
qCDebug(dcZigbeeController()) << "Start reading network parameters";
|
||||
|
||||
// This method reads all network configuration parameters sequentially. This method returns a reply which will be finished either
|
||||
// when a read request failes or all requests finished successfully.
|
||||
// If read request failes, this mehtod returns the status code of the failed request.
|
||||
|
||||
// Create an independent reply for finishing the entire read sequence
|
||||
ZigbeeInterfaceDeconzReply *readNetworkParametersReply = new ZigbeeInterfaceDeconzReply(Deconz::CommandReadParameter, m_sequenceNumber, this);
|
||||
connect(readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::finished, readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::deleteLater);
|
||||
|
||||
// Read MAC address of the bridge
|
||||
ZigbeeInterfaceDeconzReply *replyMacAddress = requestReadParameter(Deconz::ParameterMacAddress);
|
||||
connect(replyMacAddress, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyMacAddress](){
|
||||
if (replyMacAddress->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyMacAddress->command() << Deconz::ParameterMacAddress
|
||||
<< "finished with error" << replyMacAddress->statusCode();
|
||||
|
||||
readNetworkParametersReply->m_statusCode = replyMacAddress->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
QDataStream stream(replyMacAddress->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint64 macAddress = 0;
|
||||
stream >> payloadLenght >> parameter >> macAddress;
|
||||
|
||||
m_networkConfiguration.ieeeAddress = ZigbeeAddress(macAddress);
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyMacAddress->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << "IEEE address:" << m_networkConfiguration.ieeeAddress.toString();
|
||||
|
||||
// Read PAN ID
|
||||
ZigbeeInterfaceDeconzReply *replyPanId = requestReadParameter(Deconz::ParameterPanId);
|
||||
connect(replyPanId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyPanId](){
|
||||
if (replyPanId->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyPanId->command() << Deconz::ParameterPanId
|
||||
<< "finished with error" << replyPanId->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyPanId->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
QDataStream stream(replyPanId->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint16 panId = 0;
|
||||
stream >> payloadLenght >> parameter >> panId;
|
||||
|
||||
m_networkConfiguration.panId = panId;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyPanId->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << "PAN ID:" << ZigbeeUtils::convertUint16ToHexString(m_networkConfiguration.panId);
|
||||
|
||||
// Read short address
|
||||
ZigbeeInterfaceDeconzReply *replyShortAddress = requestReadParameter(Deconz::ParameterNetworkAddress);
|
||||
connect(replyShortAddress, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyShortAddress](){
|
||||
if (replyShortAddress->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyShortAddress->command() << Deconz::ParameterNetworkAddress
|
||||
<< "finished with error" << replyShortAddress->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyShortAddress->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyShortAddress->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint16 shortAddress = 0;
|
||||
stream >> payloadLenght >> parameter >> shortAddress;
|
||||
m_networkConfiguration.shortAddress = shortAddress;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyShortAddress->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << ZigbeeUtils::convertUint16ToHexString(m_networkConfiguration.shortAddress);
|
||||
|
||||
// Read extended PAN ID
|
||||
ZigbeeInterfaceDeconzReply *replyExtendedPanId = requestReadParameter(Deconz::ParameterNetworkExtendedPanId);
|
||||
connect(replyExtendedPanId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyExtendedPanId](){
|
||||
if (replyExtendedPanId->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyExtendedPanId->command() << Deconz::ParameterNetworkExtendedPanId
|
||||
<< "finished with error" << replyExtendedPanId->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyExtendedPanId->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyExtendedPanId->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint64 networkExtendedPanId = 0;
|
||||
stream >> payloadLenght >> parameter >> networkExtendedPanId;
|
||||
m_networkConfiguration.extendedPanId = networkExtendedPanId;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyExtendedPanId->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << ZigbeeUtils::convertUint64ToHexString(m_networkConfiguration.extendedPanId);
|
||||
|
||||
// Read device type
|
||||
ZigbeeInterfaceDeconzReply *replyNodeType = requestReadParameter(Deconz::ParameterNodeType);
|
||||
connect(replyNodeType, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyNodeType](){
|
||||
if (replyNodeType->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyNodeType->command() << Deconz::ParameterNodeType
|
||||
<< "finished with error" << replyNodeType->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyNodeType->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyNodeType->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint8 nodeType = 0;
|
||||
stream >> payloadLenght >> parameter >> nodeType;
|
||||
|
||||
m_networkConfiguration.nodeType = static_cast<Deconz::NodeType>(nodeType);
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyNodeType->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << m_networkConfiguration.nodeType;
|
||||
|
||||
// Read channel mask
|
||||
ZigbeeInterfaceDeconzReply *replyChannelMask = requestReadParameter(Deconz::ParameterChannelMask);
|
||||
connect(replyChannelMask, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyChannelMask](){
|
||||
if (replyChannelMask->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyChannelMask->command() << Deconz::ParameterChannelMask
|
||||
<< "finished with error" << replyChannelMask->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyChannelMask->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyChannelMask->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint32 channelMask = 0;
|
||||
stream >> payloadLenght >> parameter >> channelMask;
|
||||
|
||||
m_networkConfiguration.channelMask = channelMask;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyChannelMask->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << ZigbeeUtils::convertUint32ToHexString(m_networkConfiguration.channelMask);
|
||||
|
||||
// Read APS extended PAN ID
|
||||
ZigbeeInterfaceDeconzReply *replyApsExtendedPanId = requestReadParameter(Deconz::ParameterApsExtendedPanId);
|
||||
connect(replyApsExtendedPanId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyApsExtendedPanId](){
|
||||
if (replyApsExtendedPanId->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyApsExtendedPanId->command() << Deconz::ParameterApsExtendedPanId
|
||||
<< "finished with error" << replyApsExtendedPanId->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyApsExtendedPanId->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyApsExtendedPanId->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint64 apsExtendedPanId = 0;
|
||||
stream >> payloadLenght >> parameter >> apsExtendedPanId;
|
||||
|
||||
m_networkConfiguration.apsExtendedPanId = apsExtendedPanId;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyApsExtendedPanId->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << ZigbeeUtils::convertUint64ToHexString(m_networkConfiguration.apsExtendedPanId);
|
||||
|
||||
// Read trust center address
|
||||
ZigbeeInterfaceDeconzReply *replyTrustCenterAddress = requestReadParameter(Deconz::ParameterTrustCenterAddress);
|
||||
connect(replyTrustCenterAddress, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyTrustCenterAddress](){
|
||||
if (replyTrustCenterAddress->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyTrustCenterAddress->command() << Deconz::ParameterTrustCenterAddress
|
||||
<< "finished with error" << replyTrustCenterAddress->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyTrustCenterAddress->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyTrustCenterAddress->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint64 trustCenterAddress = 0;
|
||||
stream >> payloadLenght >> parameter >> trustCenterAddress;
|
||||
|
||||
m_networkConfiguration.trustCenterAddress = ZigbeeAddress(trustCenterAddress);
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyTrustCenterAddress->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << m_networkConfiguration.trustCenterAddress;
|
||||
|
||||
// Read security mode
|
||||
ZigbeeInterfaceDeconzReply *replySecurityMode = requestReadParameter(Deconz::ParameterSecurityMode);
|
||||
connect(replySecurityMode, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replySecurityMode](){
|
||||
if (replySecurityMode->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replySecurityMode->command() << Deconz::ParameterSecurityMode
|
||||
<< "finished with error" << replySecurityMode->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replySecurityMode->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replySecurityMode->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint8 securityMode = 0;
|
||||
stream >> payloadLenght >> parameter >> securityMode;
|
||||
|
||||
m_networkConfiguration.securityMode = static_cast<Deconz::SecurityMode>(securityMode);
|
||||
qCDebug(dcZigbeeController()) << "Request" << replySecurityMode->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << m_networkConfiguration.securityMode;
|
||||
|
||||
// Note: reading the network key returns "InavlidParameter". Might be for security reasons which is good!
|
||||
|
||||
// Read channel
|
||||
ZigbeeInterfaceDeconzReply *replyChannel = requestReadParameter(Deconz::ParameterCurrentChannel);
|
||||
connect(replyChannel, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyChannel](){
|
||||
if (replyChannel->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyChannel->command() << Deconz::ParameterCurrentChannel
|
||||
<< "finished with error" << replyChannel->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyChannel->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyChannel->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint8 channel = 0;
|
||||
stream >> payloadLenght >> parameter >> channel;
|
||||
m_networkConfiguration.currentChannel = channel;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyChannel->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << "Current channel:" << m_networkConfiguration.currentChannel;
|
||||
|
||||
|
||||
// Read permit join status
|
||||
ZigbeeInterfaceDeconzReply *replyPermitJoin = requestReadParameter(Deconz::ParameterPermitJoin);
|
||||
connect(replyPermitJoin, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyPermitJoin](){
|
||||
if (replyPermitJoin->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyPermitJoin->command() << Deconz::ParameterPermitJoin
|
||||
<< "finished with error" << replyPermitJoin->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyPermitJoin->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyPermitJoin->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0;
|
||||
stream >> payloadLenght >> parameter;
|
||||
//m_networkConfiguration.currentChannel = channel;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyPermitJoin->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully" << ZigbeeUtils::convertByteArrayToHexString(replyPermitJoin->responseData());
|
||||
|
||||
|
||||
// Read protocol version
|
||||
ZigbeeInterfaceDeconzReply *replyProtocolVersion = requestReadParameter(Deconz::ParameterProtocolVersion);
|
||||
connect(replyProtocolVersion, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyProtocolVersion](){
|
||||
if (replyProtocolVersion->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyProtocolVersion->command() << Deconz::ParameterProtocolVersion
|
||||
<< "finished with error" << replyProtocolVersion->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyProtocolVersion->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyProtocolVersion->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint16 protocolVersion = 0;
|
||||
stream >> payloadLenght >> parameter >> protocolVersion;
|
||||
m_networkConfiguration.protocolVersion = protocolVersion;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyProtocolVersion->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << "Protocol version:" << ZigbeeUtils::convertUint16ToHexString(m_networkConfiguration.protocolVersion);
|
||||
|
||||
// Read network updat id
|
||||
ZigbeeInterfaceDeconzReply *replyNetworkUpdateId = requestReadParameter(Deconz::ParameterNetworkUpdateId);
|
||||
connect(replyNetworkUpdateId, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyNetworkUpdateId](){
|
||||
if (replyNetworkUpdateId->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyNetworkUpdateId->command() << Deconz::ParameterNetworkUpdateId
|
||||
<< "finished with error" << replyNetworkUpdateId->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyNetworkUpdateId->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyNetworkUpdateId->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint8 networkUpdateId = 0;
|
||||
stream >> payloadLenght >> parameter >> networkUpdateId;
|
||||
m_networkConfiguration.networkUpdateId = networkUpdateId;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyNetworkUpdateId->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << "Network update ID:" << m_networkConfiguration.networkUpdateId;
|
||||
|
||||
// Make sure the watchdog is available for this version
|
||||
if (m_networkConfiguration.protocolVersion < 0x0108) {
|
||||
qCDebug(dcZigbeeController()) << "The watchdog api is available since protocol version 0x0108. The watchdog is not required for this version";
|
||||
m_watchdogTimer->stop();
|
||||
|
||||
// Finished reading all parameters. Finish the independent reply in order to indicate the process has finished
|
||||
readNetworkParametersReply->m_statusCode = Deconz::StatusCodeSuccess;
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Read watchdog timeout
|
||||
ZigbeeInterfaceDeconzReply *replyWatchdogTimeout = requestReadParameter(Deconz::ParameterWatchdogTtl);
|
||||
connect(replyWatchdogTimeout, &ZigbeeInterfaceDeconzReply::finished, this, [this, readNetworkParametersReply, replyWatchdogTimeout](){
|
||||
if (replyWatchdogTimeout->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << replyWatchdogTimeout->command() << Deconz::ParameterWatchdogTtl
|
||||
<< "finished with error" << replyWatchdogTimeout->statusCode();
|
||||
readNetworkParametersReply->m_statusCode = replyWatchdogTimeout->statusCode();
|
||||
readNetworkParametersReply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(replyWatchdogTimeout->responseData());
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint16 payloadLenght = 0; quint8 parameter = 0; quint32 watchdogTimeout = 0;
|
||||
stream >> payloadLenght >> parameter >> watchdogTimeout;
|
||||
m_networkConfiguration.watchdogTimeout = watchdogTimeout;
|
||||
qCDebug(dcZigbeeController()) << "Request" << replyWatchdogTimeout->command() << static_cast<Deconz::Parameter>(parameter)
|
||||
<< "finished successfully";
|
||||
qCDebug(dcZigbeeController()) << "Watchdog timeout:" << m_networkConfiguration.watchdogTimeout;
|
||||
|
||||
// Note: this value describes how much seconds are left until the watchdog triggers. Reset it right the way
|
||||
if (watchdogTimeout < 15) {
|
||||
onWatchdogTimerTimeout();
|
||||
}
|
||||
|
||||
// Finished reading all parameters. Finish the independent reply in order to indicate the process has finished
|
||||
readNetworkParametersReply->m_statusCode = Deconz::StatusCodeSuccess;
|
||||
readNetworkParametersReply->finished();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return readNetworkParametersReply;
|
||||
}
|
||||
|
||||
ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::resetWatchdog()
|
||||
{
|
||||
QByteArray parameterData;
|
||||
QDataStream stream(¶meterData, QIODevice::WriteOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
stream << m_watchdogTimeout;
|
||||
return requestWriteParameter(Deconz::ParameterWatchdogTtl, parameterData);
|
||||
}
|
||||
|
||||
void ZigbeeBridgeControllerDeconz::onInterfaceAvailableChanged(bool available)
|
||||
{
|
||||
if (available) {
|
||||
m_watchdogTimer->start();
|
||||
} else {
|
||||
m_watchdogTimer->stop();
|
||||
}
|
||||
|
||||
setAvailable(available);
|
||||
}
|
||||
|
||||
void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &package)
|
||||
{
|
||||
QDataStream stream(package);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
quint8 command = 0; quint8 sequenceNumber = 0; quint8 status = 0; quint16 frameLength = 0;
|
||||
stream >> command >> sequenceNumber >> status >> frameLength;
|
||||
|
||||
qCDebug(dcZigbeeController()) << "Interface message received"
|
||||
<< static_cast<Deconz::Command>(command)
|
||||
<< "SQN:" << sequenceNumber
|
||||
<< static_cast<Deconz::StatusCode>(status)
|
||||
<< "Frame length:" << frameLength;
|
||||
|
||||
// Check if this is an interface response for a pending reply
|
||||
if (m_pendingReplies.contains(sequenceNumber) && m_pendingReplies.value(sequenceNumber)->command() == command) {
|
||||
ZigbeeInterfaceDeconzReply *reply = m_pendingReplies.take(sequenceNumber);
|
||||
reply->m_responseData = package.right(package.length() - 5);
|
||||
reply->m_statusCode = static_cast<Deconz::StatusCode>(status);
|
||||
reply->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: we got a notification, lets set the current sequence number to the notification id,
|
||||
// so the next request will be a continuouse increase
|
||||
|
||||
m_sequenceNumber = sequenceNumber;
|
||||
|
||||
// No request for this data, lets check which notification and process the data
|
||||
}
|
||||
|
||||
void ZigbeeBridgeControllerDeconz::onWatchdogTimerTimeout()
|
||||
{
|
||||
qCDebug(dcZigbeeController()) << "Reset application watchdog on the deCONZ controller";
|
||||
ZigbeeInterfaceDeconzReply *reply = resetWatchdog();
|
||||
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [reply](){
|
||||
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Could not reset the application watchdog on the deCONZ controller." << reply->statusCode();
|
||||
return;
|
||||
}
|
||||
qCDebug(dcZigbeeController()) << "Reset application watchdog on the deCONZ controller successfully";
|
||||
});
|
||||
}
|
||||
|
||||
bool ZigbeeBridgeControllerDeconz::enable(const QString &serialPort, qint32 baudrate)
|
||||
{
|
||||
return m_interface->enable(serialPort, baudrate);
|
||||
}
|
||||
|
||||
void ZigbeeBridgeControllerDeconz::disable()
|
||||
{
|
||||
m_interface->disable();
|
||||
}
|
||||
110
libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h
Normal file
110
libnymea-zigbee/deconz/zigbeebridgecontrollerdeconz.h
Normal file
@ -0,0 +1,110 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 ZIGBEEBRIDGECONTROLLERDECONZ_H
|
||||
#define ZIGBEEBRIDGECONTROLLERDECONZ_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
#include "zigbee.h"
|
||||
#include "zigbeeaddress.h"
|
||||
#include "zigbeenetworkkey.h"
|
||||
#include "zigbeebridgecontroller.h"
|
||||
|
||||
#include "interface/deconz.h"
|
||||
#include "interface/zigbeeinterfacedeconz.h"
|
||||
#include "interface/zigbeeinterfacedeconzreply.h"
|
||||
|
||||
typedef struct DeconzNetworkConfiguration {
|
||||
ZigbeeAddress ieeeAddress; // R
|
||||
quint16 panId; // R
|
||||
quint16 shortAddress; // R
|
||||
quint64 extendedPanId; // R
|
||||
Deconz::NodeType nodeType; // RW
|
||||
quint32 channelMask; // RW
|
||||
quint64 apsExtendedPanId; // RW
|
||||
ZigbeeAddress trustCenterAddress; // RW
|
||||
Deconz::SecurityMode securityMode; // RW
|
||||
ZigbeeNetworkKey networkKey; // RW
|
||||
quint8 currentChannel; // R
|
||||
quint16 protocolVersion; // R
|
||||
quint8 networkUpdateId; // RW
|
||||
quint32 watchdogTimeout; // RW
|
||||
} DeconzNetworkConfiguration;
|
||||
|
||||
|
||||
class ZigbeeBridgeControllerDeconz : public ZigbeeBridgeController
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ZigbeeNetworkDeconz;
|
||||
|
||||
public:
|
||||
explicit ZigbeeBridgeControllerDeconz(QObject *parent = nullptr);
|
||||
~ZigbeeBridgeControllerDeconz() override;
|
||||
|
||||
ZigbeeInterfaceDeconzReply *requestVersion();
|
||||
ZigbeeInterfaceDeconzReply *requestDeviceState();
|
||||
ZigbeeInterfaceDeconzReply *requestReadParameter(Deconz::Parameter parameter);
|
||||
ZigbeeInterfaceDeconzReply *requestWriteParameter(Deconz::Parameter parameter, const QByteArray &data);
|
||||
ZigbeeInterfaceDeconzReply *requestStartJoinNetwork();
|
||||
|
||||
private:
|
||||
ZigbeeInterfaceDeconz *m_interface = nullptr;
|
||||
quint8 m_sequenceNumber = 0;
|
||||
quint32 m_watchdogTimeout = 85;
|
||||
int m_watchdogResetTimout = 60;
|
||||
QHash<quint8, ZigbeeInterfaceDeconzReply *> m_pendingReplies;
|
||||
DeconzNetworkConfiguration m_networkConfiguration;
|
||||
QTimer *m_watchdogTimer = nullptr;
|
||||
|
||||
quint8 generateSequenceNumber();
|
||||
|
||||
ZigbeeInterfaceDeconzReply *createReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent);
|
||||
|
||||
// Note: this method reads all parameters individual. The returned reply it self will not send or receive any data.
|
||||
// The data can be fetched from m_networkConfiguration on success.
|
||||
ZigbeeInterfaceDeconzReply *readNetworkParameters();
|
||||
|
||||
ZigbeeInterfaceDeconzReply *resetWatchdog();
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
void onInterfaceAvailableChanged(bool available);
|
||||
void onInterfacePackageReceived(const QByteArray &package);
|
||||
|
||||
void onWatchdogTimerTimeout();
|
||||
|
||||
public slots:
|
||||
bool enable(const QString &serialPort, qint32 baudrate);
|
||||
void disable();
|
||||
};
|
||||
|
||||
#endif // ZIGBEEBRIDGECONTROLLERDECONZ_H
|
||||
171
libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp
Normal file
171
libnymea-zigbee/deconz/zigbeenetworkdeconz.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 "zigbeenetworkdeconz.h"
|
||||
#include "loggingcategory.h"
|
||||
#include "zigbeeutils.h"
|
||||
|
||||
ZigbeeNetworkDeconz::ZigbeeNetworkDeconz(QObject *parent) :
|
||||
ZigbeeNetwork(parent)
|
||||
{
|
||||
m_controller = new ZigbeeBridgeControllerDeconz(this);
|
||||
//connect(m_controller, &ZigbeeBridgeControllerDeconz::messageReceived, this, &ZigbeeNetworkDeconz::onMessageReceived);
|
||||
connect(m_controller, &ZigbeeBridgeControllerDeconz::availableChanged, this, &ZigbeeNetworkDeconz::onControllerAvailableChanged);
|
||||
}
|
||||
|
||||
ZigbeeBridgeController *ZigbeeNetworkDeconz::bridgeController() const
|
||||
{
|
||||
if (m_controller)
|
||||
return qobject_cast<ZigbeeBridgeController *>(m_controller);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ZigbeeNode *ZigbeeNetworkDeconz::createNode(QObject *parent)
|
||||
{
|
||||
//FIXME
|
||||
Q_UNUSED(parent)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ZigbeeNetworkDeconz::setPermitJoiningInternal(bool permitJoining)
|
||||
{
|
||||
//FIXME
|
||||
Q_UNUSED(permitJoining)
|
||||
}
|
||||
|
||||
void ZigbeeNetworkDeconz::onControllerAvailableChanged(bool available)
|
||||
{
|
||||
qCDebug(dcZigbeeNetwork()) << "Hardware controller is" << (available ? "now available" : "not available");
|
||||
|
||||
if (!available) {
|
||||
// foreach (ZigbeeNode *node, nodes()) {
|
||||
// qobject_cast<ZigbeeNodeNxp *>(node)->setConnected(false);
|
||||
// }
|
||||
|
||||
setError(ErrorHardwareUnavailable);
|
||||
m_permitJoining = false;
|
||||
emit permitJoiningChanged(m_permitJoining);
|
||||
//setStartingState(StartingStateNone);
|
||||
setState(StateOffline);
|
||||
} else {
|
||||
m_error = ErrorNoError;
|
||||
m_permitJoining = false;
|
||||
emit permitJoiningChanged(m_permitJoining);
|
||||
// Note: if we are factory resetting, erase also the data on the controller before resetting
|
||||
// if (m_factoryResetting) {
|
||||
// setStartingState(StartingStateErase);
|
||||
// } else {
|
||||
// setStartingState(StartingStateReset);
|
||||
// }
|
||||
|
||||
setState(StateStarting);
|
||||
|
||||
// FIXME: do this in the startig state machine
|
||||
ZigbeeInterfaceDeconzReply *reply = m_controller->requestVersion();
|
||||
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
|
||||
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Request" << reply->command() << "finished with error" << reply->statusCode();
|
||||
// FIXME: set an appropriate error
|
||||
return;
|
||||
}
|
||||
qCDebug(dcZigbeeNetwork()) << "Version request finished" << reply->statusCode() << ZigbeeUtils::convertByteArrayToHexString(reply->responseData());
|
||||
// Note: version is an uint32 value, little endian, but we can read the individual bytes in reversed order
|
||||
quint8 majorVersion = static_cast<quint8>(reply->responseData().at(3));
|
||||
quint8 minorVersion = static_cast<quint8>(reply->responseData().at(2));
|
||||
Deconz::Platform platform = static_cast<Deconz::Platform>(reply->responseData().at(1));
|
||||
QString firmwareVersion = QString("%1.%2").arg(majorVersion).arg(minorVersion);
|
||||
qCDebug(dcZigbeeNetwork()) << "Firmware version" << firmwareVersion << platform;
|
||||
|
||||
// Read all network parameters
|
||||
ZigbeeInterfaceDeconzReply *reply = m_controller->readNetworkParameters();
|
||||
connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){
|
||||
if (reply->statusCode() != Deconz::StatusCodeSuccess) {
|
||||
qCWarning(dcZigbeeController()) << "Could not read network parameters during network start up." << reply->statusCode();
|
||||
// FIXME: set an appropriate error
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << "Reading network parameters finished successfully.";
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeNetworkDeconz::startNetwork()
|
||||
{
|
||||
loadNetwork();
|
||||
|
||||
// Check if we have to create a pan ID and select the channel
|
||||
if (extendedPanId() == 0) {
|
||||
setExtendedPanId(ZigbeeUtils::generateRandomPanId());
|
||||
qCDebug(dcZigbeeNetwork()) << "Created new PAN ID:" << extendedPanId();
|
||||
}
|
||||
|
||||
if (securityConfiguration().networkKey().isNull()) {
|
||||
qCDebug(dcZigbeeNetwork()) << "Create a new network key";
|
||||
ZigbeeNetworkKey key = ZigbeeNetworkKey::generateKey();
|
||||
m_securityConfiguration.setNetworkKey(key);
|
||||
}
|
||||
|
||||
qCDebug(dcZigbeeNetwork()) << "Using network link key" << securityConfiguration().networkKey();
|
||||
qCDebug(dcZigbeeNetwork()) << "Using global trust center link key" << securityConfiguration().globalTrustCenterLinkKey();
|
||||
|
||||
// TODO: get desired channel, by default use all
|
||||
|
||||
if (!m_controller->enable(serialPortName(), serialBaudrate())) {
|
||||
m_permitJoining = false;
|
||||
emit permitJoiningChanged(m_permitJoining);
|
||||
setState(StateOffline);
|
||||
//setStartingState(StartingStateNone);
|
||||
setError(ErrorHardwareUnavailable);
|
||||
return;
|
||||
}
|
||||
|
||||
m_permitJoining = false;
|
||||
emit permitJoiningChanged(m_permitJoining);
|
||||
// Note: wait for the controller available signal and start the initialization there
|
||||
}
|
||||
|
||||
void ZigbeeNetworkDeconz::stopNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ZigbeeNetworkDeconz::reset()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ZigbeeNetworkDeconz::factoryResetNetwork()
|
||||
{
|
||||
|
||||
}
|
||||
63
libnymea-zigbee/deconz/zigbeenetworkdeconz.h
Normal file
63
libnymea-zigbee/deconz/zigbeenetworkdeconz.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 ZIGBEENETWORKDECONZ_H
|
||||
#define ZIGBEENETWORKDECONZ_H
|
||||
|
||||
#include <QObject>
|
||||
#include "zigbeenetwork.h"
|
||||
|
||||
#include "zigbeebridgecontrollerdeconz.h"
|
||||
|
||||
class ZigbeeNetworkDeconz : public ZigbeeNetwork
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ZigbeeNetworkDeconz(QObject *parent = nullptr);
|
||||
|
||||
ZigbeeBridgeController *bridgeController() const override;
|
||||
|
||||
private:
|
||||
ZigbeeBridgeControllerDeconz *m_controller = nullptr;
|
||||
bool m_networkRunning = false;
|
||||
|
||||
protected:
|
||||
ZigbeeNode *createNode(QObject *parent) override;
|
||||
void setPermitJoiningInternal(bool permitJoining) override;
|
||||
|
||||
private slots:
|
||||
void onControllerAvailableChanged(bool available);
|
||||
|
||||
public slots:
|
||||
void startNetwork() override;
|
||||
void stopNetwork() override;
|
||||
void reset() override;
|
||||
void factoryResetNetwork() override;
|
||||
|
||||
};
|
||||
|
||||
#endif // ZIGBEENETWORKDECONZ_H
|
||||
@ -4,6 +4,10 @@ TARGET = nymea-zigbee1
|
||||
TEMPLATE = lib
|
||||
|
||||
SOURCES += \
|
||||
deconz/interface/zigbeeinterfacedeconz.cpp \
|
||||
deconz/interface/zigbeeinterfacedeconzreply.cpp \
|
||||
deconz/zigbeebridgecontrollerdeconz.cpp \
|
||||
deconz/zigbeenetworkdeconz.cpp \
|
||||
nxp/interface/zigbeeinterface.cpp \
|
||||
nxp/interface/zigbeeinterfacemessage.cpp \
|
||||
nxp/interface/zigbeeinterfacerequest.cpp \
|
||||
@ -29,6 +33,11 @@ SOURCES += \
|
||||
zigbeeaddress.cpp \
|
||||
|
||||
HEADERS += \
|
||||
deconz/interface/deconz.h \
|
||||
deconz/interface/zigbeeinterfacedeconz.h \
|
||||
deconz/interface/zigbeeinterfacedeconzreply.h \
|
||||
deconz/zigbeebridgecontrollerdeconz.h \
|
||||
deconz/zigbeenetworkdeconz.h \
|
||||
nxp/interface/zigbeeinterface.h \
|
||||
nxp/interface/zigbeeinterfacemessage.h \
|
||||
nxp/interface/zigbeeinterfacerequest.h \
|
||||
|
||||
@ -39,9 +39,9 @@ ZigbeeNetworkKey::ZigbeeNetworkKey(const ZigbeeNetworkKey &other)
|
||||
m_key = other.toByteArray();
|
||||
}
|
||||
|
||||
ZigbeeNetworkKey::ZigbeeNetworkKey(const QString &key)
|
||||
ZigbeeNetworkKey::ZigbeeNetworkKey(const QString &keyString)
|
||||
{
|
||||
QString rawKey = QString(key).remove(':');
|
||||
QString rawKey = QString(keyString).remove(':');
|
||||
if (rawKey.isEmpty())
|
||||
return;
|
||||
|
||||
@ -49,8 +49,8 @@ ZigbeeNetworkKey::ZigbeeNetworkKey(const QString &key)
|
||||
m_key = QByteArray::fromHex(rawKey.toLatin1());
|
||||
}
|
||||
|
||||
ZigbeeNetworkKey::ZigbeeNetworkKey(const QByteArray &keyString) :
|
||||
m_key(keyString)
|
||||
ZigbeeNetworkKey::ZigbeeNetworkKey(const QByteArray &key) :
|
||||
m_key(key)
|
||||
{
|
||||
Q_ASSERT_X(isValid(), "ZigbeeNetworkKey", "invalid key length in ZigbeeNetworkKey(QByteArray).");
|
||||
}
|
||||
|
||||
@ -38,8 +38,8 @@ class ZigbeeNetworkKey
|
||||
public:
|
||||
ZigbeeNetworkKey();
|
||||
ZigbeeNetworkKey(const ZigbeeNetworkKey &other);
|
||||
ZigbeeNetworkKey(const QString &key);
|
||||
ZigbeeNetworkKey(const QByteArray &keyString);
|
||||
ZigbeeNetworkKey(const QString &keyString);
|
||||
ZigbeeNetworkKey(const QByteArray &key);
|
||||
|
||||
bool isValid() const;
|
||||
bool isNull() const;
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "loggingcategory.h"
|
||||
|
||||
#include "nxp/zigbeenetworknxp.h"
|
||||
#include "deconz/zigbeenetworkdeconz.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
@ -40,6 +41,8 @@ ZigbeeNetwork *ZigbeeNetworkManager::createZigbeeNetwork(ZigbeeNetworkManager::B
|
||||
switch (backend) {
|
||||
case BackendTypeNxp:
|
||||
return qobject_cast<ZigbeeNetwork *>(new ZigbeeNetworkNxp(parent));
|
||||
case BackendTypeDeconz:
|
||||
return qobject_cast<ZigbeeNetwork *>(new ZigbeeNetworkDeconz(parent));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
@ -36,7 +36,8 @@ class ZigbeeNetworkManager
|
||||
{
|
||||
public:
|
||||
enum BackendType {
|
||||
BackendTypeNxp
|
||||
BackendTypeNxp,
|
||||
BackendTypeDeconz
|
||||
};
|
||||
|
||||
static ZigbeeNetwork *createZigbeeNetwork(BackendType backend, QObject *parent = nullptr);
|
||||
|
||||
Reference in New Issue
Block a user