diff --git a/de_web.pro b/de_web.pro index 079523ec66..62c75e9871 100644 --- a/de_web.pro +++ b/de_web.pro @@ -157,6 +157,7 @@ SOURCES = authorisation.cpp \ rest_scenes.cpp \ rest_info.cpp \ rest_capabilities.cpp \ + rest_attributes.cpp \ rule.cpp \ upnp.cpp \ permitJoin.cpp \ diff --git a/de_web_plugin.cpp b/de_web_plugin.cpp index c66e942733..b730e7f226 100644 --- a/de_web_plugin.cpp +++ b/de_web_plugin.cpp @@ -15144,6 +15144,10 @@ int DeRestPlugin::handleHttpRequest(const QHttpRequestHeader &hdr, QTcpSocket *s { ret = d->handleGatewaysApi(req, rsp); } + else if (path[2] == QLatin1String("attributes")) + { + ret = d->handleAttributesApi(req, rsp); + } else { resourceExist = false; diff --git a/de_web_plugin_private.h b/de_web_plugin_private.h index fb1741533d..2202fa35eb 100644 --- a/de_web_plugin_private.h +++ b/de_web_plugin_private.h @@ -974,6 +974,10 @@ class DeRestPluginPrivate : public QObject int handleCapabilitiesApi(const ApiRequest &req, ApiResponse &rsp); int getCapabilities(const ApiRequest &req, ApiResponse &rsp); + // REST API attributes + int handleAttributesApi(const ApiRequest &req, ApiResponse &rsp); + int writeAttribute(const ApiRequest &req, ApiResponse &rsp); + // REST API common QVariantMap errorToMap(int id, const QString &ressource, const QString &description); diff --git a/rest_attributes.cpp b/rest_attributes.cpp new file mode 100644 index 0000000000..4d38369b3a --- /dev/null +++ b/rest_attributes.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013-2019 dresden elektronik ingenieurtechnik gmbh. + * All rights reserved. + * + * The software in this package is published under the terms of the BSD + * style license a copy of which has been included with this distribution in + * the LICENSE.txt file. + * + */ + +#include +#include "de_web_plugin.h" +#include "de_web_plugin_private.h" +#include "json.h" + +int DeRestPluginPrivate::handleAttributesApi(const ApiRequest &req, ApiResponse &rsp) +{ + if (req.path[2] != QLatin1String("attributes")) + { + return REQ_NOT_HANDLED; + } + + // GET /api//attributes + if ((req.path.size() == 4) && (req.hdr.method() == "POST")) + { + return writeAttribute(req, rsp); + } + return REQ_NOT_HANDLED; +} + +/*! GET /api//attributes + \return REQ_READY_SEND + REQ_NOT_HANDLED + */ +int DeRestPluginPrivate::writeAttribute(const ApiRequest &req, ApiResponse &rsp) +{ + DBG_Assert(req.path.size() == 4); + const QString &id = req.path[3]; + bool ok; + QVariant var = Json::parse(req.content, ok); + QVariantMap map = var.toMap(); + if (!ok || map.isEmpty()) { + rsp.list.append(errorToMap(ERR_INVALID_JSON, QString("/attributes/%1").arg(id), QString("body contains invalid JSON"))); + rsp.httpStatus = HttpStatusBadRequest; + return REQ_READY_SEND; + } + if (!map.contains("key")) { + rsp.list.append(errorToMap(ERR_INVALID_VALUE, QString("/attributes/%1").arg(id), QString("key is required"))); + rsp.httpStatus = HttpStatusNotFound; + return REQ_READY_SEND; + } + if (!map.contains("value")) { + rsp.list.append(errorToMap(ERR_INVALID_VALUE, QString("/attributes/%1").arg(id), QString("value is required"))); + rsp.httpStatus = HttpStatusNotFound; + return REQ_READY_SEND; + } + + const int endpoint = 1; + const int mfcode = 0x115f; + const uint16_t key = map["key"].toInt(&ok); + const uint8_t value = map["value"].toInt(&ok); + DBG_Printf(DBG_INFO, "id: %s\n", qPrintable(id)); + DBG_Printf(DBG_INFO, "key: %d\n", key); + DBG_Printf(DBG_INFO, "value: %d\n", value); + + RestNodeBase *node = getSensorNodeForId(id); + DBG_Printf(DBG_INFO, "node unique id: %s\n", qPrintable(node->uniqueId())); + + deCONZ::ZclAttribute attr(key, deCONZ::Zcl8BitUint, "dec", deCONZ::ZclReadWrite, true); + attr.setValue((quint64)value); + if (writeAttribute(node, endpoint, BASIC_CLUSTER_ID, attr, mfcode)) { + DBG_Printf(DBG_INFO, "Write successful\n"); + rsp.list.append(QLatin1String("success")); + } else { + DBG_Printf(DBG_INFO, "Write unsuccessful\n"); + rsp.list.append(QLatin1String("failure")); + } + rsp.httpStatus = HttpStatusOk; + return REQ_READY_SEND; +}