mirror of
https://github.com/nymea/nymea-plugins.git
synced 2026-07-18 00:43:48 +02:00
added miele plugin
This commit is contained in:
parent
cdff51655f
commit
37587e6590
15
debian/control
vendored
15
debian/control
vendored
@ -494,6 +494,21 @@ Description: nymea.io plugin for a generic MQTT client
|
||||
This package will install a generic MQTT client plugin for nymea.io
|
||||
|
||||
|
||||
Package: nymea-plugin-miele
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
nymea-plugins-translations,
|
||||
Description: nymea.io plugin for Miele appliances
|
||||
The nymea daemon is a plugin based IoT (Internet of Things) server. The
|
||||
server works like a translator for devices, things and services and
|
||||
allows them to interact.
|
||||
With the powerful rule engine you are able to connect any device available
|
||||
in the system and create individual scenes and behaviors for your environment.
|
||||
.
|
||||
This package will install an integration plugin for Miele appliances.
|
||||
|
||||
|
||||
Package: nymea-plugin-netatmo
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
|
||||
1
debian/nymea-plugin-miele.install.in
vendored
Normal file
1
debian/nymea-plugin-miele.install.in
vendored
Normal file
@ -0,0 +1 @@
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginmiele.so
|
||||
5
miele/README.md
Normal file
5
miele/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Miele
|
||||
|
||||
## Requirements
|
||||
|
||||
## More
|
||||
158
miele/integrationpluginmiele.cpp
Normal file
158
miele/integrationpluginmiele.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* 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 "integrationpluginmiele.h"
|
||||
|
||||
IntegrationPluginMiele::IntegrationPluginMiele()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IntegrationPluginMiele::startPairing(ThingPairingInfo *info)
|
||||
{
|
||||
if (info->thingClassId() == mieleAccountThingClassId) {
|
||||
|
||||
QByteArray clientKey = configValue(mielePluginCustomClientKeyParamTypeId).toByteArray();
|
||||
QByteArray clientSecret = configValue(mielePluginCustomClientSecretParamTypeId).toByteArray();
|
||||
if (clientKey.isEmpty() || clientSecret.isEmpty()) {
|
||||
clientKey = apiKeyStorage()->requestKey("miele").data("clientKey");
|
||||
clientSecret = apiKeyStorage()->requestKey("miele").data("clientSecret");
|
||||
}
|
||||
if (clientKey.isEmpty() || clientSecret.isEmpty()) {
|
||||
info->finish(Thing::ThingErrorAuthenticationFailure, tr("Client key and/or seceret is not available."));
|
||||
return;
|
||||
}
|
||||
Miele *miele = new Miele(hardwareManager()->networkManager(), clientKey, clientSecret, this);
|
||||
QUrl url = miele->getLoginUrl(QUrl("https://127.0.0.1:8888"), scope);
|
||||
qCDebug(dcMiele()) << "HomeConnect url:" << url;
|
||||
m_setupHomeConnectConnections.insert(info->thingId(), miele);
|
||||
info->setOAuthUrl(url);
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
} else {
|
||||
qCWarning(dMiele()) << "Unhandled pairing metod!";
|
||||
info->finish(Thing::ThingErrorCreationMethodNotSupported);
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginMiele::confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret)
|
||||
{
|
||||
Q_UNUSED(username);
|
||||
|
||||
if (info->thingClassId() == mieleAccountThingClassId) {
|
||||
qCDebug(dcMiele()) << "Redirect url is" << secret;
|
||||
QUrl url(secret);
|
||||
QUrlQuery query(url);
|
||||
QByteArray authorizationCode = query.queryItemValue("code").toLocal8Bit();
|
||||
|
||||
Miele *miele = m_setupMieleConnections.value(info->thingId());
|
||||
if (!miele) {
|
||||
qWarning(dcMiele()) << "No Miele connection found for device:" << info->thingName();
|
||||
m_setupMieleConnections.remove(info->thingId());
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
qCDebug(dcMiele()) << "Authorization code" << authorizationCode;
|
||||
miele->getAccessTokenFromAuthorizationCode(authorizationCode);
|
||||
connect(miele, &Miele::receivedRefreshToken, info, [info, this](const QByteArray &refreshToken){
|
||||
qCDebug(dcMiele()) << "Token:" << refreshToken;
|
||||
|
||||
pluginStorage()->beginGroup(info->thingId().toString());
|
||||
pluginStorage()->setValue("refresh_token", refreshToken);
|
||||
pluginStorage()->endGroup();
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
});
|
||||
} else {
|
||||
Q_ASSERT_X(false, "confirmPairing", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginMiele::setupThing(ThingSetupInfo *info)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IntegrationPluginMiele::postSetupThing(Thing *thing)
|
||||
{
|
||||
if (!m_pluginTimer15min) {
|
||||
m_pluginTimer15min = hardwareManager()->pluginTimerManager()->registerTimer(60*15);
|
||||
connect(m_pluginTimer15min, &PluginTimer::timeout, this, [this]() {
|
||||
Q_FOREACH (Thing *thing, myThings().filterByThingClassId(mieleAccountThingClassId)) {
|
||||
Miele *miele = m_mieleConnections.value(thing);
|
||||
if (!miele) {
|
||||
qWarning(dcMiele()) << "No Miele account found for" << thing->name();
|
||||
continue;
|
||||
}
|
||||
miele->getDevices();
|
||||
Q_FOREACH (Thing *childThing, myThings().filterByParentId(thing->id())) {
|
||||
QString deviceId = childThing->paramValue(m_idParamTypeIds.value(childThing->thingClassId())).toString();
|
||||
miele->getDevice(deviceId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginMiele::executeAction(ThingActionInfo *info)
|
||||
{
|
||||
Thing *thing = info->thing();
|
||||
Action action = info->action();
|
||||
Miele *miele = m_mieleConnections.value(myThings().findById(thing->parentId()));
|
||||
if (!miele) {
|
||||
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
}
|
||||
QString haid = thing->paramValue(m_idParamTypeIds.value(thing->thingClassId())).toString();
|
||||
|
||||
if (thing->thingClassId() == ovenThingClassId) {
|
||||
|
||||
} else if (thing->thingClassId() == ovenThingClassId) {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginMiele::thingRemoved(Thing *thing)
|
||||
{
|
||||
qCDebug(dcMiele) << "Delete " << thing->name();
|
||||
|
||||
if (thing->thingClassId() == mieleAccountThingClassId) {
|
||||
m_mieleConnections.take(thing)->deleteLater();
|
||||
}
|
||||
|
||||
if (myThings().empty()) {
|
||||
if (m_pluginTimer15min) {
|
||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer15min);
|
||||
m_pluginTimer15min = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
103
miele/integrationpluginmiele.h
Normal file
103
miele/integrationpluginmiele.h
Normal file
@ -0,0 +1,103 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* 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 INTEGRATIONPLUGINMIELE_H
|
||||
#define INTEGRATIONPLUGINMIELE_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include "miele.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QDebug>
|
||||
|
||||
class IntegrationPluginMiele : public IntegrationPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginmiele.json")
|
||||
Q_INTERFACES(IntegrationPlugin)
|
||||
|
||||
public:
|
||||
explicit IntegrationPluginMiele();
|
||||
|
||||
void startPairing(ThingPairingInfo *info) override;
|
||||
void confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret) override;
|
||||
|
||||
void setupThing(ThingSetupInfo *info) override;
|
||||
void postSetupThing(Thing *thing) override;
|
||||
void executeAction(ThingActionInfo *info) override;
|
||||
void thingRemoved(Thing *thing) override;
|
||||
|
||||
void browseThing(BrowseResult *result) override;
|
||||
void browserItem(BrowserItemResult *result) override;
|
||||
void executeBrowserItem(BrowserActionInfo *info) override;
|
||||
|
||||
private:
|
||||
PluginTimer *m_pluginTimer15min = nullptr;
|
||||
|
||||
QHash<Miele *, ThingSetupInfo *> m_asyncSetup;
|
||||
|
||||
QHash<ThingId, Miele *> m_setupMieleConnections;
|
||||
QHash<Thing *, Miele *> m_mieleConnections;
|
||||
|
||||
QHash<QUuid, ThingActionInfo *> m_pendingActions;
|
||||
QHash<Thing *, QString> m_selectedProgram;
|
||||
|
||||
QHash<ThingClassId, ParamTypeId> m_idParamTypeIds;
|
||||
|
||||
QHash<ThingClassId, StateTypeId> m_connectedStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_doorStateStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_localControlStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_remoteControlActivationStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_remoteStartAllowanceStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_operationStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_doorStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_selectedProgramStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_progressStateTypeIds;
|
||||
QHash<ThingClassId, StateTypeId> m_endTimerStateTypeIds;
|
||||
|
||||
QHash<ThingClassId, ActionTypeId> m_startActionTypeIds;
|
||||
QHash<ThingClassId, ActionTypeId> m_stopActionTypeIds;
|
||||
|
||||
QHash<ThingClassId, EventTypeId> m_programFinishedEventTypeIds;
|
||||
|
||||
QHash<QString, QString> m_coffeeStrengthTypes;
|
||||
|
||||
void parseKey(Thing *thing, const QString &key, const QVariant &value);
|
||||
void parseSettingKey(Thing *thing, const QString &key, const QVariant &value);
|
||||
bool checkIfActionIsPossible(ThingActionInfo *info);
|
||||
|
||||
private slots:
|
||||
void onConnectionChanged(bool connected);
|
||||
void onAuthenticationStatusChanged(bool authenticated);
|
||||
void onRequestExecuted(QUuid requestId, bool success);
|
||||
};
|
||||
|
||||
#endif // INTEGRATIONPLUGINMIELE_H
|
||||
343
miele/integrationpluginmiele.json
Normal file
343
miele/integrationpluginmiele.json
Normal file
@ -0,0 +1,343 @@
|
||||
{
|
||||
"id": "d44fad27-668a-4540-9eee-505d0ff13c37",
|
||||
"name": "miele",
|
||||
"displayName": "Miele",
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "6ebf0bdb-012d-4277-9603-2a2e68e23c33",
|
||||
"name": "customClientKey",
|
||||
"displayName": "Custom client key",
|
||||
"defaultValue": "",
|
||||
"type": "QString"
|
||||
},
|
||||
{
|
||||
"id": "37230edb-22ed-4f1d-8849-7fd72f192d89",
|
||||
"name": "customClientSecret",
|
||||
"displayName": "Custom client secret",
|
||||
"defaultValue": "",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"apiKeys": ["miele"],
|
||||
"vendors": [
|
||||
{
|
||||
"id": "ec1e94c4-d649-4af5-90c2-6c50b1a48e9e",
|
||||
"name": "miele",
|
||||
"displayName": "Miele",
|
||||
"thingClasses": [
|
||||
{
|
||||
"id": "bea89711-7f41-4add-ba27-32dd69515c1c",
|
||||
"name": "miele",
|
||||
"displayName": "Miele",
|
||||
"interfaces": ["account"],
|
||||
"createMethods": ["user"],
|
||||
"setupMethod": "oauth",
|
||||
"paramTypes": [
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "89f4554b-fad2-402e-a0f0-6a76b26d10ea",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"id": "b38f3d86-6d54-442c-a0f3-78ece8887d93",
|
||||
"name": "loggedIn",
|
||||
"displayName": "Logged in",
|
||||
"displayNameEvent": "Logged in changed",
|
||||
"defaultValue": true,
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"id": "a5b85688-d319-4f61-8907-7da8a2b16d64",
|
||||
"name": "userDisplayName",
|
||||
"displayName": "User name",
|
||||
"displayNameEvent": "User name changed",
|
||||
"defaultValue": "",
|
||||
"type": "QString"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "cf542b5e-2903-497c-95a0-042df6535450",
|
||||
"name": "oven",
|
||||
"displayName": "Oven",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"browsable": true,
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "1e287843-41dd-49c8-a250-a21ed0e4215c",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "9c2c9360-0a4a-43ff-8d15-9cefa80380ec",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "82c7cba0-63fc-400c-8c47-dbeee47a3459",
|
||||
"name": "dishwasher",
|
||||
"displayName": "Dishwasher",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"browsable": true,
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "f61d0fef-b588-4547-a5b6-03dc1622d0c5",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "170a1bb2-7c8f-448e-acdc-61a4537f10ab",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "8af89a1f-c752-4452-a568-d3b987e4667d",
|
||||
"name": "coffeeMaker",
|
||||
"displayName": "Coffee Maker",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"browsable": true,
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "438cb528-91f4-481f-9b51-16658fd0a7c8",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "4b999b92-def7-4192-9814-38adf9af14e3",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ad9bc908-9f61-4cb3-a8df-db003c6bf171",
|
||||
"name": "dryer",
|
||||
"displayName": "Dryer",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"browsable": true,
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "3de1300c-766f-4a0b-9bc8-e75aa2402a6a",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "4dfce9b8-940b-49cb-8961-b2504fc2f3a6",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "a03e17fd-8da8-4977-8ac3-c058ada9f547",
|
||||
"name": "fridge",
|
||||
"displayName": "Fridge Freezer",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "945c1fa3-c304-4fc5-8c6b-f88f1f08d47a",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "6b066033-a290-459f-b6a1-c63857e6b538",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "58a6feaf-b2f7-48e9-822e-6f9526671f04",
|
||||
"name": "washer",
|
||||
"displayName": "Washer",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"browsable": true,
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "2681e31e-cb0a-486f-b5b7-8ae28f7c96f9",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "ba271347-04b6-40a6-86f7-9c260a2fb23f",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "bbc55426-f649-4d32-81fc-cebd8a2b46d0",
|
||||
"name": "cookTop",
|
||||
"displayName": "Cook top",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "39f094ee-b672-4d75-b106-a21eeec41a34",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "08b7960c-e244-4956-808f-53ca7e486dd9",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "707e46a5-9ca0-4375-8249-2de19ec669ec",
|
||||
"name": "hood",
|
||||
"displayName": "Hood",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "15c3cea9-16c2-4517-ae43-3a9b5f388b82",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "be91bef9-c957-4bb8-9c92-1d2a548e762f",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "5698a1cf-5b3d-4746-a4fe-e4412d2768ab",
|
||||
"name": "cleaningRobot",
|
||||
"displayName": "Cleaning robot",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "629ac68f-89a2-41cf-801b-20df9968d204",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "8abe70f4-f49f-4b13-8251-216bea230f04",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "40d31505-d6ae-4c45-a2b2-d652e1b85c80",
|
||||
"name": "cookProcessor",
|
||||
"displayName": "Cook processor",
|
||||
"interfaces": ["connectable"],
|
||||
"createMethods": ["auto"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "51750b9f-4fc3-4556-a651-c8efcf07abe7",
|
||||
"name": "id",
|
||||
"displayName": "ID",
|
||||
"defaultValue": "-",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "9eee48ba-b2e2-40fe-81b5-3404b655a497",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"defaultValue": true,
|
||||
"cached": false,
|
||||
"type": "bool"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
13
miele/meta.json
Normal file
13
miele/meta.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"title": "Miele",
|
||||
"tagline": "Connect to Miele appliances.",
|
||||
"icon": "miele.png",
|
||||
"stability": "consumer",
|
||||
"offline": false,
|
||||
"technologies": [
|
||||
"network"
|
||||
],
|
||||
"categories": [
|
||||
"online-service"
|
||||
]
|
||||
}
|
||||
133
miele/miele.cpp
Normal file
133
miele/miele.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* 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 "miele.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QUrl>
|
||||
#include <QJsonObject>
|
||||
#include <QUrlQuery>
|
||||
|
||||
void Miele::getDevices()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QUuid Miele::processAction(const QString &deviceId, Miele::ProcessAction action)
|
||||
{
|
||||
QJsonDocument doc;
|
||||
QJsonObject object;
|
||||
object.insert("processAction", action);
|
||||
doc.setObject(object);
|
||||
return putAction(deviceId, doc);
|
||||
}
|
||||
|
||||
QUuid Miele::setPower(const QString &deviceId, bool power)
|
||||
{
|
||||
QJsonDocument doc;
|
||||
QJsonObject object;
|
||||
if (power) {
|
||||
object.insert("powerOn", true);
|
||||
} else {
|
||||
object.insert("powerOff", true);
|
||||
}
|
||||
doc.setObject(object);
|
||||
return putAction(deviceId, doc);
|
||||
}
|
||||
|
||||
QUuid Miele::setDeviceName(const QString &deviceId, const QString &deviceName)
|
||||
{
|
||||
QJsonDocument doc;
|
||||
QJsonObject object;
|
||||
object.insert("description", deviceName);
|
||||
doc.setObject(object);
|
||||
return putAction(deviceId, doc);
|
||||
}
|
||||
|
||||
QUuid Miele::setLight(const QString &deviceId, bool power)
|
||||
{
|
||||
QJsonDocument doc;
|
||||
QJsonObject object;
|
||||
if (power) {
|
||||
object.insert("light", 1);
|
||||
} else {
|
||||
object.insert("light", 2);
|
||||
}
|
||||
doc.setObject(object);
|
||||
return putAction(deviceId, doc);
|
||||
}
|
||||
|
||||
QUuid Miele::setTargetTemperature(const QString &deviceId, int zone, int targetTemperature)
|
||||
{
|
||||
QJsonDocument doc;
|
||||
QJsonObject object;
|
||||
QJsonObject temperatureObj;
|
||||
temperatureObj.insert("zone", zone);
|
||||
temperatureObj.insert("value", targetTemperature);
|
||||
object.insert("targetTemperature", temperatureObj);
|
||||
doc.setObject(object);
|
||||
return putAction(deviceId, doc);
|
||||
}
|
||||
|
||||
QUuid Miele::putAction(const QString &deviceId, const QJsonDocument &action)
|
||||
{
|
||||
QUuid commandId = QUuid::createUuid();
|
||||
QUrl url = m_apiUrl;
|
||||
url.setPath("/v1/devices/"+deviceId+"/actions");
|
||||
url.setQuery("language=en");
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setRawHeader("Authorization", "Bearer "+m_accessToken);
|
||||
// request.setRawHeader("Accept-Language", "en-US");
|
||||
request.setRawHeader("accept", "application/json; charset=utf-8");
|
||||
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||
|
||||
QNetworkReply *reply = m_networkManager->put(request, action.toJson());
|
||||
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, commandId, reply]{
|
||||
|
||||
QByteArray rawData = reply->readAll();
|
||||
if (!checkStatusCode(reply, rawData)) {
|
||||
return;
|
||||
}
|
||||
QVariantMap map = QJsonDocument::fromJson(rawData).toVariant().toMap();
|
||||
qCDebug(dcMiele()) << "Send command" << map;
|
||||
if (map.contains("data")) {
|
||||
QVariantMap dataMap = map.value("data").toMap();
|
||||
qCDebug(dcMiele()) << "key" << dataMap.value("key").toString() << "value" << dataMap.value("value").toString() << dataMap.value("unit").toString();
|
||||
} else if (map.contains("error")) {
|
||||
qCWarning(dcMiele()) << "Send command" << map.value("error").toMap().value("description").toString();
|
||||
}
|
||||
emit commandExecuted(commandId, true);
|
||||
});
|
||||
return commandId;
|
||||
}
|
||||
139
miele/miele.h
Normal file
139
miele/miele.h
Normal file
@ -0,0 +1,139 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2020, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* 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 MIELE_H
|
||||
#define MIELE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "network/networkaccessmanager.h"
|
||||
|
||||
class Miele : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ProcessAction {
|
||||
ProcessActionsStart = 0,
|
||||
ProcessActionsStop,
|
||||
ProcessActionsPause,
|
||||
ProcessActionsStarSuperfreezing,
|
||||
ProcessActionsStopSuperfreezing,
|
||||
ProcessActionsStartSupercooling,
|
||||
ProcessActionsStopSupercooling
|
||||
};
|
||||
|
||||
enum Mode {
|
||||
ModeNormal,
|
||||
ModeSabbath
|
||||
};
|
||||
|
||||
enum Color {
|
||||
ColorWhite,
|
||||
ColorBlue,
|
||||
ColorRed,
|
||||
ColorYellow,
|
||||
ColorOrange,
|
||||
ColorGreen,
|
||||
ColorPink,
|
||||
ColorPurple,
|
||||
ColorTurquoise
|
||||
};
|
||||
|
||||
enum Status {
|
||||
StatusOff = 1,
|
||||
StatusOn = 2,
|
||||
StatusProgrammed = 3,
|
||||
StatusProgrammedWaitingToStart = 4,
|
||||
StatusRunnin = 5,
|
||||
StatusPause = 6,
|
||||
StatusEndProgrammed = 7,
|
||||
StatusFailure = 8,
|
||||
StatusProgrammInterrupted = 9,
|
||||
StatusIdle = 10,
|
||||
StatusRinseHold = 11,
|
||||
StatusService = 12,
|
||||
StatusSuperfreezing = 13,
|
||||
StatusSupercooling = 14,
|
||||
StatusSuperheating = 15,
|
||||
StatusSupercoolingSuperfreezing = 146,
|
||||
StatusNotConnected = 255
|
||||
};
|
||||
|
||||
Miele(NetworkAccessManager *networkmanager, const QByteArray &clientKey, const QByteArray &clientSecret, bool simulationMode = false, QObject *parent = nullptr);
|
||||
QByteArray accessToken();
|
||||
QByteArray refreshToken();
|
||||
void setSimulationMode(bool simulation);
|
||||
|
||||
QUrl getLoginUrl(const QUrl &redirectUrl, const QString &scope);
|
||||
|
||||
void getAccessTokenFromRefreshToken(const QByteArray &refreshToken);
|
||||
void getAccessTokenFromAuthorizationCode(const QByteArray &authorizationCode);
|
||||
|
||||
// INFORMATION
|
||||
void getDevices();
|
||||
void getDevice(const QString &deviceId);
|
||||
|
||||
// ACTION
|
||||
void getActions(const QString &deviceId); //The GET action is used to request a device to send the currently supported actions
|
||||
QUuid processAction(const QString &deviceId, ProcessAction action);
|
||||
|
||||
QUuid setPower(const QString &deviceId, bool power);
|
||||
QUuid setDeviceName(const QString &deviceId, const QString &deviceName);
|
||||
QUuid setLight(const QString &deviceId, bool power);
|
||||
QUuid setTargetTemperature(const QString &deviceId, int zone, int targetTemperature);
|
||||
QUuid setColors(const QString &deviceId, Color color);
|
||||
QUuid setModes(const QString &deviceId, Mode mode);
|
||||
QUuid setVentilationStep(const QString &deviceId, int step);
|
||||
QUuid setStartTime();
|
||||
|
||||
// EVENTS
|
||||
void getAllEvents();
|
||||
private:
|
||||
|
||||
NetworkAccessManager *m_networkManager = nullptr;
|
||||
|
||||
QUuid putAction(const QString &deviceId, const QJsonDocument &action); //
|
||||
|
||||
QUrl m_authorizationUrl = QUrl("https://api.mcs3.miele.com/thirdparty/login/");
|
||||
QUrl m_tokenUrl = QUrl("https://api.mcs3.miele.com/thirdparty/token/");
|
||||
QUrl m_apiUrl = QUrl("https://api.mcs3.miele.com/");
|
||||
|
||||
bool checkStatusCode(QNetworkReply *reply, const QByteArray &rawData);
|
||||
signals:
|
||||
void connectionChanged(bool connected);
|
||||
void authenticationStatusChanged(bool authenticated);
|
||||
void receivedRefreshToken(const QByteArray &refreshToken);
|
||||
void receivedAccessToken(const QByteArray &accessToken);
|
||||
void commandExecuted(const QUuid &commandId, bool success);
|
||||
};
|
||||
#endif // MIELE
|
||||
11
miele/miele.pro
Normal file
11
miele/miele.pro
Normal file
@ -0,0 +1,11 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += network
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginmiele.cpp \
|
||||
miele.cpp \
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginmiele.h \
|
||||
miele.h \
|
||||
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1">
|
||||
<context>
|
||||
<name>IntegrationPluginMiele</name>
|
||||
<message>
|
||||
<location filename="../integrationpluginmiele.cpp" line="49"/>
|
||||
<source>Client key and/or seceret is not available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -33,6 +33,7 @@ PLUGIN_DIRS = \
|
||||
lifx \
|
||||
mailnotification \
|
||||
mqttclient \
|
||||
miele \
|
||||
nanoleaf \
|
||||
netatmo \
|
||||
networkdetector \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user