added jsonrpc interface

This commit is contained in:
Simon Stürz 2015-04-23 22:35:58 +02:00 committed by Michael Zanetti
parent 1f77398681
commit 4ba4e67582
6 changed files with 355 additions and 171 deletions

View File

@ -26,10 +26,12 @@
DevicePluginTune::DevicePluginTune()
{
m_manager = new TuneManager(31337, this);
m_server = new JsonRpcServer(this);
connect(m_manager, &TuneManager::tuneConnectionStatusChanged, this, &DevicePluginTune::tuneConnectionStatusChanged);
connect(m_manager, &TuneManager::dataReady, this, &DevicePluginTune::tuneDataAvailable);
connect(m_server, &JsonRpcServer::connectionStatusChanged, this, &DevicePluginTune::tuneConnectionStatusChanged);
connect(m_server, &JsonRpcServer::gotMoodSync, this, &DevicePluginTune::updateMood);
connect(m_server, &JsonRpcServer::gotTuneSync, this, &DevicePluginTune::updateTune);
connect(m_server, &JsonRpcServer::gotActionResponse, this, &DevicePluginTune::processActionResponse);
}
DeviceManager::HardwareResources DevicePluginTune::requiredHardware() const
@ -39,12 +41,11 @@ DeviceManager::HardwareResources DevicePluginTune::requiredHardware() const
void DevicePluginTune::startMonitoringAutoDevices()
{
m_manager->start();
m_server->start();
}
DeviceManager::DeviceSetupStatus DevicePluginTune::setupDevice(Device *device)
{
// tune
if (device->deviceClassId() == tuneDeviceClassId && !tuneAlreadyAdded()) {
m_tuneDeviceId = device->id();
@ -98,88 +99,14 @@ void DevicePluginTune::deviceRemoved(Device *device)
}
sync();
}
if (device->deviceClassId() == tuneDeviceClassId && m_manager->tuneAvailable()) {
if (device->deviceClassId() == tuneDeviceClassId && m_server->tuneAvailable()) {
tuneAutodetected();
}
}
bool DevicePluginTune::sync()
{
// sync with devices with tune
if (!m_manager->tuneAvailable()) {
return false;
}
QVariantMap message;
QVariantList moods;
QVariantMap tune;
foreach (Device* device, myDevices()) {
if (device->deviceClassId() == moodDeviceClassId) {
QVariantMap mood;
mood.insert("name", device->paramValue("name"));
mood.insert("deviceId", device->id());
mood.insert("position", device->paramValue("position"));
mood.insert("icon", device->paramValue("icon"));
QVariantMap states;
states.insert("value", device->stateValue(valueStateTypeId).toInt());
states.insert("active", device->stateValue(activeStateTypeId).toBool());
mood.insert("states", states);
moods.append(mood);
}
if (device->deviceClassId() == tuneDeviceClassId) {
tune.insert("name", device->paramValue("name"));
tune.insert("deviceId", device->id());
QVariantMap states;
states.insert("value", device->stateValue(brightnessStateTypeId).toInt());
states.insert("active", device->stateValue(powerStateTypeId).toBool());
tune.insert("states", states);
}
}
message.insert("method", "Items.Sync");
message.insert("moods", moods);
message.insert("tune", tune);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(message);
QByteArray data = jsonDoc.toJson(QJsonDocument::Compact);
qDebug() << jsonDoc.toJson();
m_manager->sendData(data);
return true;
}
void DevicePluginTune::syncStates(Device *device)
{
QVariantMap message;
if (device->deviceClassId() == moodDeviceClassId) {
QVariantMap mood;
QVariantMap states;
states.insert("value", device->stateValue(valueStateTypeId).toInt());
states.insert("active", device->stateValue(activeStateTypeId).toBool());
mood.insert("states", states);
mood.insert("deviceId", device->id());
message.insert("method", "Items.SyncStates");
message.insert("mood", mood);
}
if (device->deviceClassId() == tuneDeviceClassId) {
QVariantMap tune;
QVariantMap states;
states.insert("value", device->stateValue(brightnessStateTypeId).toInt());
states.insert("active", device->stateValue(powerStateTypeId).toBool());
tune.insert("states", states);
tune.insert("deviceId", device->id());
message.insert("method", "Items.SyncStates");
message.insert("tune", tune);
}
QJsonDocument jsonDoc = QJsonDocument::fromVariant(message);
QByteArray data = jsonDoc.toJson(QJsonDocument::Compact);
m_manager->sendData(data);
return m_server->sync(myDevices());
}
bool DevicePluginTune::tuneAlreadyAdded()
@ -203,21 +130,6 @@ void DevicePluginTune::tuneAutodetected()
metaObject()->invokeMethod(this, "autoDevicesAppeared", Qt::QueuedConnection, Q_ARG(DeviceClassId, tuneDeviceClassId), Q_ARG(QList<DeviceDescriptor>, descriptorList));
}
void DevicePluginTune::activateMood(Device *device)
{
// first deactivate every current active mood
foreach (Device* d, myDevices()) {
if (d->deviceClassId() == moodDeviceClassId) {
if (d->stateValue(activeStateTypeId).toBool()) {
d->setStateValue(activeStateTypeId, false);
syncStates(d);
}
}
}
device->setStateValue(activeStateTypeId, true);
syncStates(device);
}
void DevicePluginTune::tuneConnectionStatusChanged(const bool &connected)
{
if (connected) {
@ -234,87 +146,60 @@ void DevicePluginTune::tuneConnectionStatusChanged(const bool &connected)
}
}
void DevicePluginTune::tuneDataAvailable(const QByteArray &data)
void DevicePluginTune::updateMood(const QVariantMap &message)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if(error.error != QJsonParseError::NoError) {
qDebug() << "failed to parse data" << data << ":" << error.errorString();
QVariantMap mood = message.value("mood").toMap();
Device *device = deviceManager()->findConfiguredDevice(DeviceId(mood.value("deviceId").toString()));
if (device) {
QVariantMap states = mood.value("states").toMap();
device->setStateValue(activeStateTypeId, states.value("active").toBool());
device->setStateValue(valueStateTypeId, states.value("value").toInt());
}
}
qDebug() << jsonDoc.toJson();
void DevicePluginTune::updateTune(const QVariantMap &message)
{
QVariantMap tune = message.value("tune").toMap();
Device *device = deviceManager()->findConfiguredDevice(DeviceId(tune.value("deviceId").toString()));
if (device) {
QVariantMap states = tune.value("states").toMap();
device->setStateValue(powerStateTypeId, states.value("power").toBool());
device->setStateValue(brightnessStateTypeId, states.value("brigthness").toInt());
device->setStateValue(approximationDetectedStateTypeId, states.value("approximationDetected").toBool());
device->setStateValue(lightIntensityStateTypeId, states.value("lightIntensity").toInt());
device->setStateValue(humidityStateTypeId, states.value("humidity").toInt());
device->setStateValue(temperatureStateTypeId, states.value("temperature").toDouble());
}
}
QVariantMap message = jsonDoc.toVariant().toMap();
if (message.value("method").toString() == "Items.SyncStates") {
if (message.contains("mood")) {
QVariantMap mood = message.value("mood").toMap();
Device *device = deviceManager()->findConfiguredDevice(DeviceId(mood.value("deviceId").toString()));
if (device) {
qDebug() << "update device" << device->name();
QVariantMap states = mood.value("states").toMap();
bool activeValue = states.value("active").toBool();
int value = states.value("value").toInt();
if (activeValue) {
activateMood(device);
} else {
device->setStateValue(activeStateTypeId, activeValue);
}
device->setStateValue(valueStateTypeId, value);
}
}
if (message.contains("tune")) {
QVariantMap tune = message.value("tune").toMap();
Device *device = deviceManager()->findConfiguredDevice(DeviceId(tune.value("deviceId").toString()));
if (device) {
QVariantMap states = tune.value("states").toMap();
device->setStateValue(powerStateTypeId, states.value("active").toBool());
device->setStateValue(brightnessStateTypeId, states.value("value").toInt());
device->setStateValue(approximationDetectedStateTypeId, states.value("approximationDetected").toBool());
device->setStateValue(lightIntensityStateTypeId, states.value("lightIntensity").toInt());
device->setStateValue(humidityStateTypeId, states.value("humidity").toInt());
device->setStateValue(temperatureStateTypeId, states.value("temperature").toDouble());
}
}
void DevicePluginTune::processActionResponse(const QVariantMap &message)
{
bool success = message.value("success").toBool();
ActionId actionId = ActionId(message.value("params").toMap().value("actionId").toString());
if (success) {
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorNoError);
} else {
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorHardwareFailure);
}
}
DeviceManager::DeviceError DevicePluginTune::executeAction(Device *device, const Action &action)
{
if (!m_manager->tuneAvailable()) {
if (!m_server->tuneAvailable()) {
return DeviceManager::DeviceErrorHardwareNotAvailable;
}
// Mood
if (device->deviceClassId() == moodDeviceClassId) {
if (action.actionTypeId() == activeActionTypeId) {
bool currentState = device->stateValue(activeStateTypeId).toBool();
device->setStateValue(activeStateTypeId, !currentState);
syncStates(device);
return DeviceManager::DeviceErrorNoError;
}
if (action.actionTypeId() == valueActionTypeId) {
device->setStateValue(valueStateTypeId, action.param("percentage").value().toInt());
syncStates(device);
return DeviceManager::DeviceErrorNoError;
}
if (device->deviceClassId() != moodDeviceClassId || device->deviceClassId() != tuneDeviceClassId) {
return DeviceManager::DeviceErrorDeviceClassNotFound;
}
if (action.actionTypeId() != powerActionTypeId ||
action.actionTypeId() != brightnessActionTypeId ||
action.actionTypeId() != valueActionTypeId){
return DeviceManager::DeviceErrorActionTypeNotFound;
}
if (device->deviceClassId() == tuneDeviceClassId) {
if (action.actionTypeId() == powerActionTypeId) {
bool currentState = device->stateValue(powerStateTypeId).toBool();
device->setStateValue(powerStateTypeId, !currentState);
syncStates(device);
return DeviceManager::DeviceErrorNoError;
}
if (action.actionTypeId() == brightnessActionTypeId) {
device->setStateValue(brightnessStateTypeId, action.param("brightness").value().toInt());
syncStates(device);
return DeviceManager::DeviceErrorNoError;
}
}
return DeviceManager::DeviceErrorDeviceClassNotFound;
m_server->executeAction(device, action);
return DeviceManager::DeviceErrorAsync;
}

View File

@ -20,7 +20,9 @@
#define DEVICEPLUGINTUNE_H
#include "plugin/deviceplugin.h"
#include "tunemanager.h"
#include "jsonrpcserver.h"
class JsonRpcServer;
class DevicePluginTune : public DevicePlugin
{
@ -39,18 +41,18 @@ public:
void deviceRemoved(Device *device) override;
private:
TuneManager *m_manager;
JsonRpcServer *m_server;
DeviceId m_tuneDeviceId;
bool sync();
void syncStates(Device *device);
bool tuneAlreadyAdded();
void tuneAutodetected();
void activateMood(Device* device);
private slots:
void tuneConnectionStatusChanged(const bool &connected);
void tuneDataAvailable(const QByteArray &data);
void updateMood(const QVariantMap &message);
void updateTune(const QVariantMap &message);
void processActionResponse(const QVariantMap &message);
public slots:
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;

View File

@ -0,0 +1,232 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "jsonrpcserver.h"
extern PluginId pluginId;
extern DeviceClassId moodDeviceClassId;
extern StateTypeId activeStateTypeId;
extern ActionTypeId activeActionTypeId;
extern StateTypeId valueStateTypeId;
extern ActionTypeId valueActionTypeId;
extern DeviceClassId tuneDeviceClassId;
extern StateTypeId reachableStateTypeId;
extern StateTypeId approximationDetectedStateTypeId;
extern StateTypeId temperatureStateTypeId;
extern StateTypeId humidityStateTypeId;
extern StateTypeId lightIntensityStateTypeId;
extern StateTypeId powerStateTypeId;
extern ActionTypeId powerActionTypeId;
extern StateTypeId brightnessStateTypeId;
extern ActionTypeId brightnessActionTypeId;
JsonRpcServer::JsonRpcServer(QObject *parent) :
QObject(parent),
m_id(0)
{
m_manager = new TuneManager(31337, this);
connect(m_manager, &TuneManager::tuneConnectionStatusChanged, this, &JsonRpcServer::connectionStatusChanged);
connect(m_manager, &TuneManager::dataReady, this, &JsonRpcServer::processData);
}
void JsonRpcServer::start()
{
m_manager->start();
}
void JsonRpcServer::stop()
{
m_manager->stop();
}
bool JsonRpcServer::tuneAvailable()
{
return m_manager->tuneAvailable();
}
bool JsonRpcServer::sync(QList<Device *> deviceList)
{
if (!tuneAvailable()) {
return false;
}
QVariantMap message;
QVariantMap params;
QVariantList moods;
QVariantMap tune;
foreach (Device* device, deviceList) {
if (device->deviceClassId() == moodDeviceClassId) {
QVariantMap mood;
mood.insert("name", device->paramValue("name"));
mood.insert("deviceId", device->id());
mood.insert("position", device->paramValue("position"));
mood.insert("icon", device->paramValue("icon"));
QVariantMap states;
states.insert("value", device->stateValue(valueStateTypeId).toInt());
states.insert("active", device->stateValue(activeStateTypeId).toBool());
mood.insert("states", states);
moods.append(mood);
}
if (device->deviceClassId() == tuneDeviceClassId) {
tune.insert("name", device->paramValue("name"));
tune.insert("deviceId", device->id());
tune.insert("brightness", device->stateValue(brightnessStateTypeId).toInt());
tune.insert("power", device->stateValue(powerStateTypeId).toBool());
}
}
m_id++;
params.insert("moods", moods);
params.insert("tune", tune);
message.insert("method", "Items.Sync");
message.insert("id", m_id);
message.insert("params", params);
m_requests.insert(m_id, message);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(message);
qDebug() << jsonDoc.toJson();
m_manager->sendData(jsonDoc.toJson(QJsonDocument::Compact));
return true;
}
void JsonRpcServer::executeAction(Device *device, const Action &action)
{
QVariantMap message;
QVariantMap params;
params.insert("deviceId", device->deviceClassId());
params.insert("actionId", action.id());
if (device->deviceClassId() == moodDeviceClassId) {
message.insert("method", "Mood.ExecuteAction");
if (action.actionTypeId() == valueActionTypeId) {
params.insert("value", action.param("percentage").value().toInt());
params.insert("active", device->stateValue(activeStateTypeId).toBool());
} else if (action.actionTypeId() == activeActionTypeId) {
params.insert("value", device->stateValue(valueStateTypeId).toInt());
params.insert("active", action.param("active").value().toBool());
}
} else if(device->deviceClassId() == tuneDeviceClassId) {
message.insert("method", "Tune.ExecuteAction");
if (action.actionTypeId() == valueActionTypeId) {
params.insert("brightness", action.param("brightness").value().toInt());
params.insert("power", device->stateValue(powerStateTypeId).toBool());
} else if (action.actionTypeId() == activeActionTypeId) {
params.insert("brightness", device->stateValue(brightnessStateTypeId).toInt());
params.insert("power", action.param("power").value().toBool());
}
}
m_id++;
message.insert("id", m_id);
message.insert("params", params);
m_requests.insert(m_id, message);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(message);
qDebug() << jsonDoc.toJson();
m_manager->sendData(jsonDoc.toJson(QJsonDocument::Compact));
}
QByteArray JsonRpcServer::formatResponse(int commandId, const QVariantMap &responseParams)
{
QVariantMap responseMap;
responseMap.insert("id", commandId);
responseMap.insert("success", true);
responseMap.insert("params", responseParams);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(responseMap);
return jsonDoc.toJson(QJsonDocument::Compact);
}
QByteArray JsonRpcServer::formatErrorResponse(int commandId, const QString &errorMessage)
{
QVariantMap responseMap;
responseMap.insert("id", commandId);
responseMap.insert("success", false);
responseMap.insert("error", errorMessage);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(responseMap);
return jsonDoc.toJson(QJsonDocument::Compact);
}
void JsonRpcServer::handleResponse(const QVariantMap &response)
{
int responseId = response.value("id").toInt();
if (!m_requests.contains(responseId)) {
qWarning() << "ERROR: got a response without a corresponding request!!!!";
return;
}
// remove it request since we have a response now...
QVariantMap request = m_requests.take(responseId);
// Note: maby we have to do something if any request fails
if (!response.value("success").toBool()) {
qWarning() << "ERROR: for request:" << request << response.value("error").toString();
}
// check if this is a response to an action execution
if (response.contains("actionId")) {
emit gotActionResponse(response);
}
}
void JsonRpcServer::processData(const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if(error.error != QJsonParseError::NoError) {
qDebug() << "failed to parse data" << data << ":" << error.errorString();
return;
}
QVariantMap message = jsonDoc.toVariant().toMap();
// check if the message has an id
if (!message.contains("id")) {
qWarning() << "ERROR: message does not contain a valid id" << message;
return;
}
// if this is a response message to a request
if (message.contains("success") && !message.contains("method")) {
handleResponse(message);
return;
}
// otherwise we need a method
if (!message.contains("method")) {
qWarning() << "ERROR: message does not contain a valid method" << message;
return;
}
int commandId = message.value("id").toInt();
if (message.value("method").toString() == "Mood.SyncStates") {
emit gotMoodSync(message.value("params").toMap());
m_manager->sendData(formatResponse(commandId));
}
if (message.value("method").toString() == "Tune.SyncStates") {
emit gotTuneSync(message.value("params").toMap());
m_manager->sendData(formatResponse(commandId));
}
}

View File

@ -0,0 +1,63 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef JSONRPCSERVER_H
#define JSONRPCSERVER_H
#include <QObject>
#include <QDebug>
#include <QJsonDocument>
#include "tunemanager.h"
#include "plugin/device.h"
#include "types/action.h"
class JsonRpcServer : public QObject
{
Q_OBJECT
public:
explicit JsonRpcServer(QObject *parent = 0);
void start();
void stop();
bool tuneAvailable();
bool sync(QList<Device *> deviceList);
void executeAction(Device* device, const Action &action);
private:
TuneManager *m_manager;
int m_id;
QHash<int, QVariantMap> m_requests;
QByteArray formatResponse(int commandId, const QVariantMap &responseParams = QVariantMap());
QByteArray formatErrorResponse(int commandId, const QString &errorMessage);
void handleResponse(const QVariantMap &response);
signals:
void connectionStatusChanged(const bool &connectionStatus);
void gotTuneSync(const QVariantMap &params);
void gotMoodSync(const QVariantMap &params);
void gotActionResponse(const QVariantMap &response);
private slots:
void processData(const QByteArray &data);
};
#endif // JSONRPCSERVER_H

View File

@ -4,10 +4,13 @@ TARGET = $$qtLibraryTarget(guh_deviceplugintune)
SOURCES += \
deviceplugintune.cpp \
tunemanager.cpp
tunemanager.cpp \
jsonrpcserver.cpp
HEADERS += \
deviceplugintune.h \
tunemanager.h
tunemanager.h \
jsonrpcserver.h

View File

@ -76,7 +76,6 @@ void TuneManager::readData()
QByteArray message;
while (m_tune->canReadLine()) {
QByteArray dataLine = m_tune->readLine();
//qDebug() << " --> tune line in:" << dataLine;
message.append(dataLine);
if (dataLine.endsWith('\n')) {
emit dataReady(message);