diff --git a/nymea-plugins.pro b/nymea-plugins.pro index d0802476..05ad8ac1 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -49,6 +49,7 @@ PLUGIN_DIRS = \ openuv \ openweathermap \ osdomotics \ + owlet \ philipshue \ powerfox \ pushbullet \ diff --git a/owlet/owletclient.cpp b/owlet/owletclient.cpp new file mode 100644 index 00000000..cefd9494 --- /dev/null +++ b/owlet/owletclient.cpp @@ -0,0 +1,90 @@ +#include "owletclient.h" + +#include "extern-plugininfo.h" + +#include +#include + +OwletClient::OwletClient(QObject *parent) : QObject(parent) +{ + +} + +void OwletClient::connectToHost(const QHostAddress &address, int port) +{ + if (m_socket) { + m_socket->abort(); + m_socket->deleteLater(); + } + + m_socket = new QTcpSocket(this); + connect(m_socket, &QTcpSocket::connected, this, [this](){ + emit connected(); + }); + connect(m_socket, &QTcpSocket::disconnected, this, [this, address, port](){ + qCDebug(dcOwlet()) << "Disconnected from owleet"; + emit disconnected(); + QTimer::singleShot(1000, this, [=]{ + connectToHost(address, port); + }); + + }); + connect(m_socket, &QTcpSocket::errorOccurred, this, [this](){ + qCDebug(dcOwlet()) << "Error in owlet communication"; + emit error(); + }); + + connect(m_socket, &QTcpSocket::readyRead, this, [this](){ + dataReceived(m_socket->readAll()); + }); + m_socket->connectToHost(address, port); +} + +int OwletClient::sendCommand(const QString &method, const QVariantMap ¶ms) +{ + if (!m_socket) { + qCWarning(dcOwlet()) << "Not connected to owlet. Not sending command."; + return -1; + } + + int id = ++m_commandId; + + QVariantMap packet; + packet.insert("id", id); + packet.insert("method", method); + packet.insert("params", params); + m_socket->write(QJsonDocument::fromVariant(packet).toJson(QJsonDocument::Compact)); + return id; +} + +void OwletClient::dataReceived(const QByteArray &data) +{ + m_receiveBuffer.append(data); + + int splitIndex = m_receiveBuffer.indexOf("}\n{") + 1; + if (splitIndex <= 0) { + splitIndex = m_receiveBuffer.length(); + } + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(m_receiveBuffer.left(splitIndex), &error); + if (error.error != QJsonParseError::NoError) { + // qWarning() << "Could not parse json data from nymea" << m_receiveBuffer.left(splitIndex) << error.errorString(); + return; + } + // qDebug() << "received response" << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented)); + m_receiveBuffer = m_receiveBuffer.right(m_receiveBuffer.length() - splitIndex - 1); + if (!m_receiveBuffer.isEmpty()) { + staticMetaObject.invokeMethod(this, "dataReceived", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray())); + } + + QVariantMap packet = jsonDoc.toVariant().toMap(); + + if (packet.contains("notification")) { + qCDebug(dcOwlet()) << "Notification received:" << packet; + emit notificationReceived(packet.value("notification").toString(), packet.value("params").toMap()); + } else if (packet.contains("id")) { + qCDebug(dcOwlet()) << "reply received:" << packet; + int id = packet.value("id").toInt(); + emit replyReceived(id, packet.value("params").toMap()); + } +} diff --git a/owlet/owletclient.h b/owlet/owletclient.h new file mode 100644 index 00000000..289374de --- /dev/null +++ b/owlet/owletclient.h @@ -0,0 +1,37 @@ +#ifndef OWLETCLIENT_H +#define OWLETCLIENT_H + +#include +#include +#include + +class OwletClient : public QObject +{ + Q_OBJECT +public: + explicit OwletClient(QObject *parent = nullptr); + + void connectToHost(const QHostAddress &address, int port); + + int sendCommand(const QString &method, const QVariantMap ¶ms); + +signals: + void connected(); + void disconnected(); + void error(); + + void replyReceived(int commandId, const QVariantMap ¶ms); + void notificationReceived(const QString &name, const QVariantMap ¶ms); + +private slots: + void dataReceived(const QByteArray &data); + +private: + QTcpSocket *m_socket = nullptr; + int m_commandId = 0; + + QByteArray m_receiveBuffer; + +}; + +#endif // OWLETCLIENT_H