somfytahoma: Use local connection "Somfy Developer Mode"

Change the plugin from cloud based to local access.
master
Christian Fetzer 2022-05-20 10:48:06 +02:00
parent 1f411c2244
commit 4cf1449524
7 changed files with 439 additions and 494 deletions

View File

@ -1,7 +1,11 @@
# Somfy TaHoma
This plugin adds support for Somfy smarthome devices through the Somfy TaHoma
API.
This plugin adds support for Somfy smarthome devices through the local
Somfy TaHoma API offered by Somfy Gateways with 'Developer Mode'
enabled.
See <https://developer.somfy.com/developer-mode> and <https://github.com/Somfy-Developer/Somfy-TaHoma-Developer-Mode>
for more information.
## Prerequisites

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -35,128 +35,176 @@
#include <QJsonArray>
#include "network/networkaccessmanager.h"
#include "network/zeroconf/zeroconfservicebrowser.h"
#include "platform/platformzeroconfcontroller.h"
#include "plugininfo.h"
#include "somfytahomarequests.h"
void IntegrationPluginSomfyTahoma::init()
{
m_zeroConfBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_kizboxdev._tcp");
}
void IntegrationPluginSomfyTahoma::discoverThings(ThingDiscoveryInfo *info)
{
foreach (const ZeroConfServiceEntry &entry, m_zeroConfBrowser->serviceEntries()) {
qCDebug(dcSomfyTahoma()) << "Found local gateway:" << entry;
ThingDescriptor descriptor(info->thingClassId(), "Somfy Tahoma Gateway", entry.hostAddress().toString());
ParamList params;
params << Param(gatewayThingGatewayIdParamTypeId, entry.name());
params << Param(gatewayThingGatewayPinParamTypeId, entry.txt("gateway_pin"));
descriptor.setParams(params);
Things existingThings = myThings().filterByParam(gatewayThingGatewayIdParamTypeId, entry.name());
if (existingThings.count() == 1) {
qCDebug(dcSomfyTahoma()) << "This gateway already exists in the system!";
descriptor.setThingId(existingThings.first()->id());
}
info->addThingDescriptor(descriptor);
}
info->finish(Thing::ThingErrorNoError);
}
void IntegrationPluginSomfyTahoma::startPairing(ThingPairingInfo *info)
{
info->finish(Thing::ThingErrorNoError, QT_TR_NOOP("Please enter the login credentials for Somfy Tahoma."));
info->finish(Thing::ThingErrorNoError, QT_TR_NOOP("Please enter the cloud login credentials for Somfy Tahoma in order to set up local access to the Gateway."));
}
void IntegrationPluginSomfyTahoma::confirmPairing(ThingPairingInfo *info, const QString &username, const QString &password)
{
SomfyTahomaRequest *request = createSomfyTahomaLoginRequest(hardwareManager()->networkManager(), username, password, this);
// Request local token from cloud account.
SomfyTahomaRequest *request = createCloudSomfyTahomaLoginRequest(hardwareManager()->networkManager(), username, password, this);
connect(request, &SomfyTahomaRequest::error, info, [info](){
info->finish(Thing::ThingErrorAuthenticationFailure, QT_TR_NOOP("Failed to login to Somfy Tahoma."));
});
connect(request, &SomfyTahomaRequest::finished, info, [this, info, username, password](const QVariant &/*result*/){
pluginStorage()->beginGroup(info->thingId().toString());
pluginStorage()->setValue("username", username);
pluginStorage()->setValue("password", password);
pluginStorage()->endGroup();
info->finish(Thing::ThingErrorNoError);
SomfyTahomaRequest *request = createCloudSomfyTahomaGetRequest(hardwareManager()->networkManager(), "/config/" + info->params().paramValue(gatewayThingGatewayPinParamTypeId).toString() + "/local/tokens/generate", this);
connect(request, &SomfyTahomaRequest::error, info, [info](){
info->finish(Thing::ThingErrorAuthenticationFailure, QT_TR_NOOP("Failed to generate token."));
});
connect(request, &SomfyTahomaRequest::finished, info, [this, info, username, password](const QVariant &result){
QString token = result.toMap()["token"].toString();
QJsonDocument jsonRequest{QJsonObject{
{"label", "nymea"},
{"token", token},
{"scope", "devmode"},
}};
SomfyTahomaRequest *request = createCloudSomfyTahomaPostRequest(hardwareManager()->networkManager(), "/config/" + info->params().paramValue(gatewayThingGatewayPinParamTypeId).toString() + "/local/tokens", "application/json", jsonRequest.toJson(QJsonDocument::Compact), this);
connect(request, &SomfyTahomaRequest::error, info, [info](){
info->finish(Thing::ThingErrorAuthenticationFailure, QT_TR_NOOP("Failed to activate token."));
});
connect(request, &SomfyTahomaRequest::finished, info, [this, info, username, password, token](const QVariant &result){
qCDebug(dcSomfyTahoma()) << "Got token uuid" << result;
QString requestId = result.toMap()["requestId"].toString();
pluginStorage()->beginGroup(info->thingId().toString());
pluginStorage()->setValue("username", username);
pluginStorage()->setValue("password", password);
pluginStorage()->setValue("token", token);
pluginStorage()->setValue("tokenRequestId", requestId);
pluginStorage()->endGroup();
info->finish(Thing::ThingErrorNoError);
});
});
});
}
void IntegrationPluginSomfyTahoma::setupThing(ThingSetupInfo *info)
{
if (info->thing()->thingClassId() == tahomaThingClassId) {
SomfyTahomaRequest *request = createLoginRequestWithStoredCredentials(info->thing());
// Compatibility to older cloud based versions of the plugin.
if (info->thing()->thingClassId() == tahomaThingClassId ||
(info->thing()->thingClassId() == gatewayThingClassId && getToken(info->thing()).isEmpty())) {
info->finish(Thing::ThingErrorSetupFailed, QT_TR_NOOP("The Somfy Plugin switched to local connection. Please enable 'Developer Mode' on somfy.com, remove the account from Nymea and re-setup the Somfy Tahoma Gateway."));
return;
}
if (info->thing()->thingClassId() == gatewayThingClassId) {
SomfyTahomaRequest *request = createLocalSomfyTahomaGetRequest(hardwareManager()->networkManager(), getHost(info->thing()), getToken(info->thing()), "/setup", this);
connect(request, &SomfyTahomaRequest::error, info, [info](){
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Failed to login to Somfy Tahoma."));
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Failed to connect to gateway."));
});
connect(request, &SomfyTahomaRequest::finished, info, [this, info](const QVariant &/*result*/){
QUuid accountId = info->thing()->id();
SomfyTahomaRequest *request = createSomfyTahomaGetRequest(hardwareManager()->networkManager(), "/setup", this);
connect(request, &SomfyTahomaRequest::finished, this, [this, accountId](const QVariant &result){
QList<ThingDescriptor> unknownDevices;
foreach (const QVariant &gatewayVariant, result.toMap()["gateways"].toList()) {
QVariantMap gatewayMap = gatewayVariant.toMap();
QString gatewayId = gatewayMap.value("gatewayId").toString();
Thing *thing = myThings().findByParams(ParamList() << Param(gatewayThingGatewayIdParamTypeId, gatewayId));
connect(request, &SomfyTahomaRequest::finished, info, [info, this](const QVariant &result){
QList<ThingDescriptor> unknownDevices;
QUuid gatewayId = info->thing()->id();
info->thing()->setParamValue(gatewayThingGatewayIdParamTypeId, result.toMap()["gateways"].toList().first().toMap().value("gatewayId").toString());
foreach (const QVariant &deviceVariant, result.toMap()["devices"].toList()) {
QVariantMap deviceMap = deviceVariant.toMap();
QString type = deviceMap.value("controllableName").toString();
QString deviceUrl = deviceMap.value("deviceURL").toString();
QString label = deviceMap.value("label").toString();
if (type.startsWith(QStringLiteral("io:RollerShutter"))) {
Thing *thing = myThings().findByParams(ParamList() << Param(rollershutterThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing gateway:" << gatewayId;
qCDebug(dcSomfyTahoma()) << "Found existing roller shutter:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found new gateway:" << gatewayId;
ThingDescriptor descriptor(gatewayThingClassId, "TaHoma Gateway", QString(), accountId);
descriptor.setParams(ParamList() << Param(gatewayThingGatewayIdParamTypeId, gatewayId));
qCInfo(dcSomfyTahoma()) << "Found new roller shutter:" << label << deviceUrl;
ThingDescriptor descriptor(rollershutterThingClassId, label, QString(), gatewayId);
descriptor.setParams(ParamList() << Param(rollershutterThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
}
foreach (const QVariant &deviceVariant, result.toMap()["devices"].toList()) {
QVariantMap deviceMap = deviceVariant.toMap();
QString type = deviceMap.value("uiClass").toString();
QString deviceUrl = deviceMap.value("deviceURL").toString();
QString label = deviceMap.value("label").toString();
if (type == QStringLiteral("RollerShutter")) {
Thing *thing = myThings().findByParams(ParamList() << Param(rollershutterThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing roller shutter:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found new roller shutter:" << label << deviceUrl;
ThingDescriptor descriptor(rollershutterThingClassId, label, QString(), accountId);
descriptor.setParams(ParamList() << Param(rollershutterThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
} else if (type == QStringLiteral("ExteriorVenetianBlind")) {
Thing *thing = myThings().findByParams(ParamList() << Param(venetianblindThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing venetian blind:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found new venetian blind:" << label << deviceUrl;
ThingDescriptor descriptor(venetianblindThingClassId, label, QString(), accountId);
descriptor.setParams(ParamList() << Param(venetianblindThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
} else if (type == QStringLiteral("GarageDoor")) {
Thing *thing = myThings().findByParams(ParamList() << Param(garagedoorThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing garage door:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found new garage door:" << label << deviceUrl;
ThingDescriptor descriptor(garagedoorThingClassId, label, QString(), accountId);
descriptor.setParams(ParamList() << Param(garagedoorThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
} else if (type == QStringLiteral("Awning")) {
Thing *thing = myThings().findByParams(ParamList() << Param(awningThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing awning:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found new awning:" << label << deviceUrl;
ThingDescriptor descriptor(awningThingClassId, label, QString(), accountId);
descriptor.setParams(ParamList() << Param(awningThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
} else if (type == QStringLiteral("Light") && (deviceUrl.startsWith("io"))) {
Thing *thing = myThings().findByParams(ParamList() << Param(lightThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing light:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found new light:" << label << deviceUrl;
ThingDescriptor descriptor(lightThingClassId, label, QString(), accountId);
descriptor.setParams(ParamList() << Param(lightThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
} else if (type == QStringLiteral("ProtocolGateway") ||
type == QStringLiteral("Alarm") ||
(type == QStringLiteral("Light") && deviceUrl.startsWith("hue"))) {
continue;
} else if (type == QStringLiteral("io:ExteriorVenetianBlindIOComponent")) {
Thing *thing = myThings().findByParams(ParamList() << Param(venetianblindThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing venetian blind:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found unsupperted Somfy device:" << label << type << deviceUrl;
qCInfo(dcSomfyTahoma()) << "Found new venetian blind:" << label << deviceUrl;
ThingDescriptor descriptor(venetianblindThingClassId, label, QString(), gatewayId);
descriptor.setParams(ParamList() << Param(venetianblindThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
} else if (type == QStringLiteral("io:GarageOpenerIOComponent")) {
Thing *thing = myThings().findByParams(ParamList() << Param(garagedoorThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing garage door:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found new garage door:" << label << deviceUrl;
ThingDescriptor descriptor(garagedoorThingClassId, label, QString(), gatewayId);
descriptor.setParams(ParamList() << Param(garagedoorThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
} else if (type == QStringLiteral("io:HorizontalAwningIOComponent")) {
Thing *thing = myThings().findByParams(ParamList() << Param(awningThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing awning:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found new awning:" << label << deviceUrl;
ThingDescriptor descriptor(awningThingClassId, label, QString(), gatewayId);
descriptor.setParams(ParamList() << Param(awningThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
} else if (type == QStringLiteral("io:DimmableLightIOComponent")) {
Thing *thing = myThings().findByParams(ParamList() << Param(lightThingDeviceUrlParamTypeId, deviceUrl));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Found existing light:" << label << deviceUrl;
} else {
qCInfo(dcSomfyTahoma()) << "Found new light:" << label << deviceUrl;
ThingDescriptor descriptor(lightThingClassId, label, QString(), gatewayId);
descriptor.setParams(ParamList() << Param(lightThingDeviceUrlParamTypeId, deviceUrl));
unknownDevices.append(descriptor);
}
} else if (type == QStringLiteral("io:StackComponent") ||
type.startsWith("internal:")) {
continue;
} else {
qCInfo(dcSomfyTahoma()) << "Found unsupperted Somfy device:" << label << type << deviceUrl;
}
if (!unknownDevices.isEmpty()) {
emit autoThingsAppeared(unknownDevices);
}
});
}
info->finish(Thing::ThingErrorNoError);
if (!unknownDevices.isEmpty()) {
emit autoThingsAppeared(unknownDevices);
}
});
}
else if (info->thing()->thingClassId() == gatewayThingClassId ||
info->thing()->thingClassId() == rollershutterThingClassId ||
else if (info->thing()->thingClassId() == rollershutterThingClassId ||
info->thing()->thingClassId() == venetianblindThingClassId ||
info->thing()->thingClassId() == garagedoorThingClassId ||
info->thing()->thingClassId() == awningThingClassId ||
@ -167,105 +215,39 @@ void IntegrationPluginSomfyTahoma::setupThing(ThingSetupInfo *info)
void IntegrationPluginSomfyTahoma::postSetupThing(Thing *thing)
{
if (thing->thingClassId() == tahomaThingClassId) {
pluginStorage()->beginGroup(thing->id().toString());
thing->setStateValue(tahomaUserDisplayNameStateTypeId, pluginStorage()->value("username"));
pluginStorage()->endGroup();
refreshAccount(thing);
if (thing->thingClassId() != gatewayThingClassId) {
return;
}
// Set parent of all devices to the respective gateway. We create all devices in setup() of the account.
// But we don't have the ThingIds of the gateways, because they're created in setup() as well.
QUrl deviceUrl;
if (thing->thingClassId() == rollershutterThingClassId) {
deviceUrl = QUrl(thing->paramValue(rollershutterThingDeviceUrlParamTypeId).toString());
} else if (thing->thingClassId() == venetianblindThingClassId) {
deviceUrl = QUrl(thing->paramValue(venetianblindThingDeviceUrlParamTypeId).toString());
} else if (thing->thingClassId() == garagedoorThingClassId) {
deviceUrl = QUrl(thing->paramValue(garagedoorThingDeviceUrlParamTypeId).toString());
} else if (thing->thingClassId() == awningThingClassId) {
deviceUrl = QUrl(thing->paramValue(awningThingDeviceUrlParamTypeId).toString());
} else if (thing->thingClassId() == lightThingClassId) {
deviceUrl = QUrl(thing->paramValue(lightThingDeviceUrlParamTypeId).toString());
}
if (!deviceUrl.isEmpty()) {
Thing *gateway = myThings().findByParams(ParamList() << Param(gatewayThingGatewayIdParamTypeId, deviceUrl.host()));
if (gateway) {
thing->setParentId(gateway->parentId());
} else {
qCWarning(dcSomfyTahoma()) << "Couldn't find gateway for thing" << thing;
}
}
}
void IntegrationPluginSomfyTahoma::refreshAccount(Thing *thing)
{
// Ensure that even't polling doesn't interfere the refreshing.
if (m_eventPollTimer.contains(thing)) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_eventPollTimer[thing]);
}
SomfyTahomaRequest *setupRequest = createSomfyTahomaGetRequest(hardwareManager()->networkManager(), "/setup", this);
// Call /setup and update the state of all devices
SomfyTahomaRequest *setupRequest = createLocalSomfyTahomaGetRequest(hardwareManager()->networkManager(), getHost(thing), getToken(thing), "/setup", this);
connect(setupRequest, &SomfyTahomaRequest::error, this, [this, thing](){
markDisconnected(thing);
});
connect(setupRequest, &SomfyTahomaRequest::finished, this, [this, thing](const QVariant &result){
thing->setStateValue(tahomaLoggedInStateTypeId, true);
thing->setStateValue(tahomaConnectedStateTypeId, true);
foreach (const QVariant &gatewayVariant, result.toMap()["gateways"].toList()) {
QVariantMap gatewayMap = gatewayVariant.toMap();
QString gatewayId = gatewayMap.value("gatewayId").toString();
Thing *thing = myThings().findByParams(ParamList() << Param(gatewayThingGatewayIdParamTypeId, gatewayId));
if (thing) {
qCDebug(dcSomfyTahoma()) << "Setting initial state for gateway:" << gatewayId;
thing->setStateValue(gatewayConnectedStateTypeId, gatewayMap["connectivity"].toMap()["status"] == "OK");
pluginStorage()->beginGroup(thing->id().toString());
pluginStorage()->setValue("connected", gatewayMap["connectivity"].toMap()["status"] == "OK");
pluginStorage()->endGroup();
}
}
thing->setStateValue(gatewayConnectedStateTypeId, true);
foreach (const QVariant &deviceVariant, result.toMap()["devices"].toList()) {
updateThingStates(deviceVariant.toMap()["deviceURL"].toString(), deviceVariant.toMap()["states"].toList());
}
});
SomfyTahomaRequest *eventRegistrationRequest = createSomfyTahomaPostRequest(hardwareManager()->networkManager(), "/events/register", "application/json", QByteArray(), this);
// Register event handler
SomfyTahomaRequest *eventRegistrationRequest = createLocalSomfyTahomaPostRequest(hardwareManager()->networkManager(), getHost(thing), getToken(thing), "/events/register", "application/json", QByteArray(), this);
connect(eventRegistrationRequest, &SomfyTahomaRequest::error, this, [this, thing](){
qCWarning(dcSomfyTahoma()) << "Failed to register for events.";
markDisconnected(thing);
});
connect(eventRegistrationRequest, &SomfyTahomaRequest::finished, this, [this, thing](const QVariant &result){
thing->setStateValue(tahomaConnectedStateTypeId, true);
QString eventListenerId = result.toMap()["id"].toString();
m_eventPollTimer[thing] = hardwareManager()->pluginTimerManager()->registerTimer(2 /*sec*/);
connect(m_eventPollTimer[thing], &PluginTimer::timeout, thing, [this, thing, eventListenerId](){
SomfyTahomaRequest *eventFetchRequest = createSomfyTahomaEventFetchRequest(hardwareManager()->networkManager(), eventListenerId, this);
SomfyTahomaRequest *eventFetchRequest = createLocalSomfyTahomaEventFetchRequest(hardwareManager()->networkManager(), getHost(thing), getToken(thing), eventListenerId, this);
connect(eventFetchRequest, &SomfyTahomaRequest::error, thing, [this, thing](QNetworkReply::NetworkError error){
qCWarning(dcSomfyTahoma()) << "Failed to fetch events:" << error;
markDisconnected(thing);
if (error == QNetworkReply::AuthenticationRequiredError) {
qCInfo(dcSomfyTahoma()) << "Failed to fetch events: Authentication expired, reauthenticating";
SomfyTahomaRequest *request = createLoginRequestWithStoredCredentials(thing);
connect(request, &SomfyTahomaRequest::error, this, [this, thing](){
// This is a fatal error. The user needs to reconfigure the account to provide new credentials.
qCWarning(dcSomfyTahoma()) << "Failed to reauthenticate";
hardwareManager()->pluginTimerManager()->unregisterTimer(m_eventPollTimer[thing]);
m_eventPollTimer.remove(thing);
});
connect(request, &SomfyTahomaRequest::finished, this, [this, thing](const QVariant &/*result*/){
qCInfo(dcSomfyTahoma()) << "Reauthentication successful";
refreshAccount(thing);
});
} else {
qCWarning(dcSomfyTahoma()) << "Failed to fetch events:" << error;
}
});
connect(eventFetchRequest, &SomfyTahomaRequest::finished, thing, [this, thing](const QVariant &result){
thing->setStateValue(tahomaConnectedStateTypeId, true);
thing->setStateValue(gatewayConnectedStateTypeId, true);
restoreChildConnectedState(thing);
if (!result.toList().empty()) {
qCDebug(dcSomfyTahoma()) << "Got events:" << qUtf8Printable(QJsonDocument::fromVariant(result).toJson());
}
handleEvents(result.toList());
});
});
@ -275,13 +257,61 @@ void IntegrationPluginSomfyTahoma::refreshAccount(Thing *thing)
void IntegrationPluginSomfyTahoma::thingRemoved(Thing *thing)
{
m_eventPollTimer.remove(thing);
if (thing->thingClassId() != gatewayThingClassId) {
return;
}
// Unregister local token from cloud account.
pluginStorage()->beginGroup(thing->id().toString());
QString username = pluginStorage()->value("username").toString();
QString password = pluginStorage()->value("password").toString();
QString requestId = pluginStorage()->value("tokenRequestId").toString();
QString gatewayPin = thing->paramValue(gatewayThingGatewayPinParamTypeId).toString();
pluginStorage()->endGroup();
SomfyTahomaRequest *request = createCloudSomfyTahomaLoginRequest(hardwareManager()->networkManager(), username, password, this);
connect(request, &SomfyTahomaRequest::error, this, [](){
qCWarning(dcSomfyTahoma()) << "Failed to login to Somfy Tahoma cloud for deleting the Token.";
});
connect(request, &SomfyTahomaRequest::finished, this, [this, gatewayPin, requestId](const QVariant &/*result*/){
SomfyTahomaRequest *request = createCloudSomfyTahomaDeleteRequest(hardwareManager()->networkManager(), "/config/" + gatewayPin + "/local/tokens/" + requestId, this);
connect(request, &SomfyTahomaRequest::finished, this, [](const QVariant &/*result*/){
qCInfo(dcSomfyTahoma()) << "Deleted Token from Somfy Tahoma cloud.";
});
});
}
void IntegrationPluginSomfyTahoma::handleEvents(const QVariantList &eventList)
void IntegrationPluginSomfyTahoma::handleEvents(const QVariantList &events)
{
Thing *thing;
foreach (const QVariant &eventVariant, eventList) {
foreach (const QVariant &eventVariant, events) {
QVariantMap eventMap = eventVariant.toMap();
QString device = eventMap["deviceURL"].toString();
thing = myThings().findByParams(ParamList() << Param(rollershutterThingDeviceUrlParamTypeId, eventMap["deviceURL"]));
if (thing) {
device = thing->name();
}
thing = myThings().findByParams(ParamList() << Param(venetianblindThingDeviceUrlParamTypeId, eventMap["deviceURL"]));
if (thing) {
device = thing->name();
}
thing = myThings().findByParams(ParamList() << Param(garagedoorThingDeviceUrlParamTypeId, eventMap["deviceURL"]));
if (thing) {
device = thing->name();
}
thing = myThings().findByParams(ParamList() << Param(awningThingDeviceUrlParamTypeId, eventMap["deviceURL"]));
if (thing) {
device = thing->name();
}
thing = myThings().findByParams(ParamList() << Param(lightThingDeviceUrlParamTypeId, eventMap["deviceURL"]));
if (thing) {
device = thing->name();
}
qCDebug(dcSomfyTahoma()) << "Got event" << eventMap["name"].toString() << "for device" << device;
qCDebug(dcSomfyTahoma()) << qUtf8Printable(QJsonDocument::fromVariant(eventVariant).toJson());
if (eventMap["name"] == "DeviceStateChangedEvent") {
updateThingStates(eventMap["deviceURL"].toString(), eventMap["deviceStates"].toList());
} else if (eventMap["name"] == "ExecutionRegisteredEvent") {
@ -340,30 +370,6 @@ void IntegrationPluginSomfyTahoma::handleEvents(const QVariantList &eventList)
thingActionInfo->finish(Thing::ThingErrorHardwareFailure);
}
}
} else if (eventMap["name"] == "GatewayAliveEvent") {
thing = myThings().findByParams(ParamList() << Param(gatewayThingGatewayIdParamTypeId, eventMap["gatewayId"]));
if (thing) {
qCInfo(dcSomfyTahoma()) << "Gateway connected event received:" << eventMap["gatewayId"];
thing->setStateValue(gatewayConnectedStateTypeId, true);
pluginStorage()->beginGroup(thing->id().toString());
pluginStorage()->setValue("connected", true);
pluginStorage()->endGroup();
restoreChildConnectedState(thing);
} else {
qCDebug(dcSomfyTahoma()) << "Ignoring gateway connected event for unknown gateway" << eventMap["gatewayId"];
}
} else if (eventMap["name"] == "GatewayDownEvent") {
thing = myThings().findByParams(ParamList() << Param(gatewayThingGatewayIdParamTypeId, eventMap["gatewayId"]));
if (thing) {
qCInfo(dcSomfyTahoma()) << "Gateway disconnected event received:" << eventMap["gatewayId"];
thing->setStateValue(gatewayConnectedStateTypeId, false);
pluginStorage()->beginGroup(thing->id().toString());
pluginStorage()->setValue("connected", false);
pluginStorage()->endGroup();
markDisconnected(thing);
} else {
qCDebug(dcSomfyTahoma()) << "Ignoring gateway disconnected event for unknown gateway" << eventMap["gatewayId"];
}
}
}
}
@ -551,7 +557,7 @@ void IntegrationPluginSomfyTahoma::executeAction(ThingActionInfo *info)
{"commands", QJsonArray{QJsonObject{{"name", actionName},
{"parameters", actionParameters}}}}}}}
}};
SomfyTahomaRequest *request = createSomfyTahomaPostRequest(hardwareManager()->networkManager(), "/exec/apply", "application/json", jsonRequest.toJson(QJsonDocument::Compact), this);
SomfyTahomaRequest *request = createLocalSomfyTahomaPostRequest(hardwareManager()->networkManager(), getHost(info->thing()), getToken(info->thing()), "/exec/apply", "application/json", jsonRequest.toJson(QJsonDocument::Compact), this);
connect(request, &SomfyTahomaRequest::error, info, [info](){
info->finish(Thing::ThingErrorHardwareFailure);
});
@ -564,20 +570,9 @@ void IntegrationPluginSomfyTahoma::executeAction(ThingActionInfo *info)
}
}
SomfyTahomaRequest *IntegrationPluginSomfyTahoma::createLoginRequestWithStoredCredentials(Thing *thing)
{
pluginStorage()->beginGroup(thing->id().toString());
QString username = pluginStorage()->value("username").toString();
QString password = pluginStorage()->value("password").toString();
pluginStorage()->endGroup();
return createSomfyTahomaLoginRequest(hardwareManager()->networkManager(), username, password, this);
}
void IntegrationPluginSomfyTahoma::markDisconnected(Thing *thing)
{
if (thing->thingClassId() == tahomaThingClassId) {
thing->setStateValue(tahomaConnectedStateTypeId, false);
} else if (thing->thingClassId() == gatewayThingClassId) {
if (thing->thingClassId() == gatewayThingClassId) {
thing->setStateValue(gatewayConnectedStateTypeId, false);
} else if (thing->thingClassId() == rollershutterThingClassId) {
thing->setStateValue(rollershutterConnectedStateTypeId, false);
@ -599,9 +594,7 @@ void IntegrationPluginSomfyTahoma::restoreChildConnectedState(Thing *thing)
{
pluginStorage()->beginGroup(thing->id().toString());
if (pluginStorage()->contains("connected")) {
if (thing->thingClassId() == gatewayThingClassId) {
thing->setStateValue(gatewayConnectedStateTypeId, pluginStorage()->value("connected").toBool());
} else if (thing->thingClassId() == rollershutterThingClassId) {
if (thing->thingClassId() == rollershutterThingClassId) {
thing->setStateValue(rollershutterConnectedStateTypeId, pluginStorage()->value("connected").toBool());
} else if (thing->thingClassId() == venetianblindThingClassId) {
thing->setStateValue(venetianblindConnectedStateTypeId, pluginStorage()->value("connected").toBool());
@ -618,3 +611,46 @@ void IntegrationPluginSomfyTahoma::restoreChildConnectedState(Thing *thing)
restoreChildConnectedState(child);
}
}
QString IntegrationPluginSomfyTahoma::getHost(Thing *thing) const
{
Thing *gateway = thing;
if (!thing->parentId().isNull()) {
gateway = myThings().findById(thing->parentId());
}
QString gatewayId = gateway->paramValue(gatewayThingGatewayIdParamTypeId).toString();
ZeroConfServiceEntry zeroConfEntry;
foreach (const ZeroConfServiceEntry &entry, m_zeroConfBrowser->serviceEntries()) {
if (entry.name() == gatewayId) {
zeroConfEntry = entry;
}
}
QString host;
pluginStorage()->beginGroup(gateway->id().toString());
if (zeroConfEntry.isValid()) {
host = zeroConfEntry.hostAddress().toString() + ":" + QString::number(zeroConfEntry.port());
pluginStorage()->setValue("cachedAddress", host);
} else if (pluginStorage()->contains("cachedAddress")){
host = pluginStorage()->value("cachedAddress").toString();
} else {
qCWarning(dcSomfyTahoma()) << "Unable to determine IP address for:" << gatewayId;
}
pluginStorage()->endGroup();
return host;
}
QString IntegrationPluginSomfyTahoma::getToken(Thing *thing) const
{
Thing *gateway = thing;
if (!thing->parentId().isNull()) {
gateway = myThings().findById(thing->parentId());
}
QString token;
pluginStorage()->beginGroup(gateway->id().toString());
token = pluginStorage()->value("token").toString();
pluginStorage()->endGroup();
return token;
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -34,6 +34,12 @@
#include "integrations/integrationplugin.h"
#include "plugintimer.h"
#include "extern-plugininfo.h"
class QHostAddress;
class ZeroConfServiceBrowser;
class SomfyTahomaRequest;
class IntegrationPluginSomfyTahoma : public IntegrationPlugin
@ -44,6 +50,9 @@ class IntegrationPluginSomfyTahoma : public IntegrationPlugin
Q_INTERFACES(IntegrationPlugin)
public:
void init() override;
void discoverThings(ThingDiscoveryInfo *info) override;
void startPairing(ThingPairingInfo *info) override;
void confirmPairing(ThingPairingInfo *info, const QString &username, const QString &password) override;
@ -54,14 +63,16 @@ public:
void executeAction(ThingActionInfo *info) override;
private:
SomfyTahomaRequest *createLoginRequestWithStoredCredentials(Thing *thing);
void refreshAccount(Thing *thing);
void handleEvents(const QVariantList &eventList);
void refreshGateway(Thing *thing);
void handleEvents(const QVariantList &events);
void updateThingStates(const QString &deviceUrl, const QVariantList &stateList);
void markDisconnected(Thing *thing);
void restoreChildConnectedState(Thing *thing);
QString getHost(Thing *thing) const;
QString getToken(Thing *thing) const;
private:
ZeroConfServiceBrowser *m_zeroConfBrowser = nullptr;
QMap<Thing *, PluginTimer *> m_eventPollTimer;
QMap<QString, QPointer<ThingActionInfo>> m_pendingActions;
QMap<QString, QList<Thing *>> m_currentExecutions;

View File

@ -12,8 +12,7 @@
"id": "fedd72b8-547d-4e4f-b73e-71344a8ba0c1",
"name": "tahoma",
"displayName": "Tahoma Account",
"createMethods": ["user"],
"setupMethod": "userandpassword",
"createMethods": ["auto"],
"interfaces": ["account"],
"stateTypes": [
{
@ -46,14 +45,23 @@
"id": "6c09e0b9-f0cc-4dea-9994-9e039eff78f1",
"name": "gateway",
"displayName": "Tahoma Gateway",
"createMethods": ["auto"],
"createMethods": ["discovery"],
"setupMethod": "userandpassword",
"interfaces": ["gateway"],
"paramTypes": [
{
"id": "e321a7d6-6dcb-4a37-baf1-c7008f2d5bdb",
"displayName": "Gateway Id",
"name": "gatewayId",
"type": "QString"
"type": "QString",
"readOnly": true
},
{
"id": "30b73244-e5bb-4c00-9332-702a60c03420",
"displayName": "Gateway pin",
"name": "gatewayPin",
"type": "QString",
"readOnly": true
}
],
"stateTypes": [

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -38,7 +38,8 @@
#include "extern-plugininfo.h"
static const QString somfyTahomaUrl = QStringLiteral("https://tahomalink.com/enduser-mobile-web/enduserAPI");
static const QString somfyTahomaWebUrl = QStringLiteral("https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI");
static const QString localSomfyTahomaPath = QStringLiteral("/enduser-mobile-web/1/enduserAPI");
SomfyTahomaRequest::SomfyTahomaRequest(QNetworkReply *reply, QObject *parent) : QObject(parent)
{
@ -64,32 +65,73 @@ SomfyTahomaRequest::SomfyTahomaRequest(QNetworkReply *reply, QObject *parent) :
});
}
SomfyTahomaRequest *createSomfyTahomaPostRequest(NetworkAccessManager *networkManager, const QString &path, const QString &contentType, const QByteArray &body, QObject *parent)
SomfyTahomaRequest *createCloudSomfyTahomaPostRequest(NetworkAccessManager *networkManager, const QString &path, const QString &contentType, const QByteArray &body, QObject *parent)
{
QUrl url(somfyTahomaUrl + path);
QUrl url(somfyTahomaWebUrl + path);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, contentType);
QNetworkReply *reply = networkManager->post(request, body);
return new SomfyTahomaRequest(reply, parent);
}
SomfyTahomaRequest *createSomfyTahomaGetRequest(NetworkAccessManager *networkManager, const QString &path, QObject *parent)
SomfyTahomaRequest *createCloudSomfyTahomaGetRequest(NetworkAccessManager *networkManager, const QString &path, QObject *parent)
{
QUrl url(somfyTahomaUrl + path);
QUrl url(somfyTahomaWebUrl + path);
QNetworkRequest request(url);
QNetworkReply *reply = networkManager->get(request);
return new SomfyTahomaRequest(reply, parent);
}
SomfyTahomaRequest *createSomfyTahomaLoginRequest(NetworkAccessManager *networkManager, const QString &username, const QString &password, QObject *parent)
SomfyTahomaRequest *createCloudSomfyTahomaDeleteRequest(NetworkAccessManager *networkManager, const QString &path, QObject *parent)
{
QUrl url(somfyTahomaWebUrl + path);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::KnownHeaders::ContentLengthHeader, 0);
QNetworkReply *reply = networkManager->deleteResource(request);
return new SomfyTahomaRequest(reply, parent);
}
SomfyTahomaRequest *createCloudSomfyTahomaLoginRequest(NetworkAccessManager *networkManager, const QString &username, const QString &password, QObject *parent)
{
QUrlQuery postData;
postData.addQueryItem("userId", username);
postData.addQueryItem("userPassword", password);
return createSomfyTahomaPostRequest(networkManager, "/login", "application/x-www-form-urlencoded", postData.toString(QUrl::FullyEncoded).toUtf8(), parent);
return createCloudSomfyTahomaPostRequest(networkManager, "/login", "application/x-www-form-urlencoded", postData.toString(QUrl::FullyEncoded).toUtf8(), parent);
}
SomfyTahomaRequest *createSomfyTahomaEventFetchRequest(NetworkAccessManager *networkManager, const QString &eventListenerId, QObject *parent)
SomfyTahomaRequest *createLocalSomfyTahomaPostRequest(NetworkAccessManager *networkManager, const QString &host, const QString &token, const QString &path, const QString &contentType, const QByteArray &body, QObject *parent)
{
return createSomfyTahomaPostRequest(networkManager, "/events/" + eventListenerId + "/fetch", "application/json", QByteArray(), parent);
QUrl url("https://" + host + localSomfyTahomaPath + path);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, contentType);
request.setRawHeader("Authorization", "Bearer " + token.toUtf8());
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(config);
QNetworkReply *reply = networkManager->post(request, body);
return new SomfyTahomaRequest(reply, parent);
}
SomfyTahomaRequest *createLocalSomfyTahomaGetRequest(NetworkAccessManager *networkManager, const QString &host, const QString &token, const QString &path, QObject *parent)
{
QUrl url("https://" + host + localSomfyTahomaPath + path);
QNetworkRequest request(url);
request.setRawHeader("Authorization", "Bearer " + token.toUtf8());
QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(config);
QNetworkReply *reply = networkManager->get(request);
return new SomfyTahomaRequest(reply, parent);
}
SomfyTahomaRequest *createLocalSomfyTahomaEventFetchRequest(NetworkAccessManager *networkManager, const QString &host, const QString &token, const QString &eventListenerId, QObject *parent)
{
return createLocalSomfyTahomaPostRequest(networkManager, host, token, "/events/" + eventListenerId + "/fetch", "application/json", QByteArray(), parent);
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -47,9 +47,14 @@ signals:
void finished(const QVariant &results);
};
SomfyTahomaRequest *createSomfyTahomaPostRequest(NetworkAccessManager *networkManager, const QString &path, const QString &contentType, const QByteArray &body, QObject *parent);
SomfyTahomaRequest *createSomfyTahomaGetRequest(NetworkAccessManager *networkManager, const QString &path, QObject *parent);
SomfyTahomaRequest *createSomfyTahomaLoginRequest(NetworkAccessManager *networkManager, const QString &username, const QString &password, QObject *parent);
SomfyTahomaRequest *createSomfyTahomaEventFetchRequest(NetworkAccessManager *networkManager, const QString &eventListenerId, QObject *parent);
SomfyTahomaRequest *createCloudSomfyTahomaPostRequest(NetworkAccessManager *networkManager, const QString &path, const QString &contentType, const QByteArray &body, QObject *parent);
SomfyTahomaRequest *createCloudSomfyTahomaGetRequest(NetworkAccessManager *networkManager, const QString &path, QObject *parent);
SomfyTahomaRequest *createCloudSomfyTahomaDeleteRequest(NetworkAccessManager *networkManager, const QString &path, QObject *parent);
SomfyTahomaRequest *createCloudSomfyTahomaLoginRequest(NetworkAccessManager *networkManager, const QString &username, const QString &password, QObject *parent);
SomfyTahomaRequest *createLocalSomfyTahomaPostRequest(NetworkAccessManager *networkManager, const QString &host, const QString &token, const QString &path, const QString &contentType, const QByteArray &body, QObject *parent);
SomfyTahomaRequest *createLocalSomfyTahomaGetRequest(NetworkAccessManager *networkManager, const QString &host, const QString &token, const QString &path, QObject *parent);
SomfyTahomaRequest *createLocalSomfyTahomaEventFetchRequest(NetworkAccessManager *networkManager, const QString &host, const QString &token, const QString &eventListenerId, QObject *parent);
#endif // SOMFYTAHOMAREQUESTS_H

View File

@ -4,66 +4,67 @@
<context>
<name>IntegrationPluginSomfyTahoma</name>
<message>
<location filename="../integrationpluginsomfytahoma.cpp" line="44"/>
<source>Please enter the login credentials for Somfy Tahoma.</source>
<location filename="../integrationpluginsomfytahoma.cpp" line="74"/>
<source>Please enter the cloud login credentials for Somfy Tahoma in order to set up local access to the Gateway.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginsomfytahoma.cpp" line="51"/>
<location filename="../integrationpluginsomfytahoma.cpp" line="67"/>
<location filename="../integrationpluginsomfytahoma.cpp" line="82"/>
<source>Failed to login to Somfy Tahoma.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginsomfytahoma.cpp" line="87"/>
<source>Failed to generate token.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginsomfytahoma.cpp" line="98"/>
<source>Failed to activate token.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginsomfytahoma.cpp" line="122"/>
<source>The Somfy Plugin switched to local connection. Please enable &apos;Developer Mode&apos; on somfy.com, remove the account from Nymea and re-setup the Somfy Tahoma Gateway.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginsomfytahoma.cpp" line="129"/>
<source>Failed to connect to gateway.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SomfyTahoma</name>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="144"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="147"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="150"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="93"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="96"/>
<source>Angle</source>
<extracomment>The name of the ParamType (ThingClass: venetianblind, ActionType: angle, ID: {079c7a80-8a1c-4fd7-b40c-6800120c70fb})
----------
The name of the ParamType (ThingClass: venetianblind, EventType: angle, ID: {079c7a80-8a1c-4fd7-b40c-6800120c70fb})
----------
The name of the StateType ({079c7a80-8a1c-4fd7-b40c-6800120c70fb}) of ThingClass venetianblind</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="153"/>
<source>Angle changed</source>
<extracomment>The name of the EventType ({079c7a80-8a1c-4fd7-b40c-6800120c70fb}) of ThingClass venetianblind</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="156"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="99"/>
<source>Awning</source>
<extracomment>The name of the ThingClass ({d3a3bb40-4b2d-4bdc-989f-5254f03b4c90})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="159"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="162"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="165"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="102"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="105"/>
<source>Brightness</source>
<extracomment>The name of the ParamType (ThingClass: light, ActionType: brightness, ID: {1b51ce68-1f7e-4f06-b68d-bfca2d61b353})
----------
The name of the ParamType (ThingClass: light, EventType: brightness, ID: {1b51ce68-1f7e-4f06-b68d-bfca2d61b353})
----------
The name of the StateType ({1b51ce68-1f7e-4f06-b68d-bfca2d61b353}) of ThingClass light</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="168"/>
<source>Brightness changed</source>
<extracomment>The name of the EventType ({1b51ce68-1f7e-4f06-b68d-bfca2d61b353}) of ThingClass light</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="171"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="174"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="177"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="180"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="108"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="111"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="114"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="117"/>
<source>Close</source>
<extracomment>The name of the ActionType ({20cae53b-f36d-425b-b937-3e46519893a3}) of ThingClass awning
----------
@ -75,80 +76,35 @@ The name of the ActionType ({baf377c6-9fba-44cf-9f14-af0101f874b5}) of ThingClas
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="183"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="186"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="189"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="192"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="195"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="198"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="201"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="204"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="207"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="210"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="213"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="216"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="219"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="222"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="120"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="123"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="126"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="129"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="132"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="135"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="138"/>
<source>Connected</source>
<extracomment>The name of the ParamType (ThingClass: light, EventType: connected, ID: {fb8dcd84-70ad-4f3e-97c4-93296608e33d})
----------
The name of the StateType ({fb8dcd84-70ad-4f3e-97c4-93296608e33d}) of ThingClass light
----------
The name of the ParamType (ThingClass: awning, EventType: connected, ID: {8f972969-10dd-4954-9c8b-de56070a6668})
<extracomment>The name of the StateType ({fb8dcd84-70ad-4f3e-97c4-93296608e33d}) of ThingClass light
----------
The name of the StateType ({8f972969-10dd-4954-9c8b-de56070a6668}) of ThingClass awning
----------
The name of the ParamType (ThingClass: garagedoor, EventType: connected, ID: {5a32cbd3-bc1c-4724-ae53-9f36cb75bf84})
----------
The name of the StateType ({5a32cbd3-bc1c-4724-ae53-9f36cb75bf84}) of ThingClass garagedoor
----------
The name of the ParamType (ThingClass: venetianblind, EventType: connected, ID: {57361115-edbe-49fb-9847-408b571d3108})
----------
The name of the StateType ({57361115-edbe-49fb-9847-408b571d3108}) of ThingClass venetianblind
----------
The name of the ParamType (ThingClass: rollershutter, EventType: connected, ID: {7a49865d-5ea5-43be-b61f-4e454c48e87e})
----------
The name of the StateType ({7a49865d-5ea5-43be-b61f-4e454c48e87e}) of ThingClass rollershutter
----------
The name of the ParamType (ThingClass: gateway, EventType: connected, ID: {18ba7fb7-c9e8-4c61-86b3-a8d3b825ed00})
----------
The name of the StateType ({18ba7fb7-c9e8-4c61-86b3-a8d3b825ed00}) of ThingClass gateway
----------
The name of the ParamType (ThingClass: tahoma, EventType: connected, ID: {10ebf650-a93a-4ee3-945b-fba10d4e35a5})
----------
The name of the StateType ({10ebf650-a93a-4ee3-945b-fba10d4e35a5}) of ThingClass tahoma</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="225"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="228"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="231"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="234"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="237"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="240"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="243"/>
<source>Connetion state changed</source>
<extracomment>The name of the EventType ({fb8dcd84-70ad-4f3e-97c4-93296608e33d}) of ThingClass light
----------
The name of the EventType ({8f972969-10dd-4954-9c8b-de56070a6668}) of ThingClass awning
----------
The name of the EventType ({5a32cbd3-bc1c-4724-ae53-9f36cb75bf84}) of ThingClass garagedoor
----------
The name of the EventType ({57361115-edbe-49fb-9847-408b571d3108}) of ThingClass venetianblind
----------
The name of the EventType ({7a49865d-5ea5-43be-b61f-4e454c48e87e}) of ThingClass rollershutter
----------
The name of the EventType ({18ba7fb7-c9e8-4c61-86b3-a8d3b825ed00}) of ThingClass gateway
----------
The name of the EventType ({10ebf650-a93a-4ee3-945b-fba10d4e35a5}) of ThingClass tahoma</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="246"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="249"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="252"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="255"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="258"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="141"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="144"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="147"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="150"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="153"/>
<source>Device URL</source>
<extracomment>The name of the ParamType (ThingClass: light, Type: thing, ID: {9cd2e0f2-a02f-478a-9358-6ff0f5aba9f5})
----------
@ -162,85 +118,49 @@ The name of the ParamType (ThingClass: rollershutter, Type: thing, ID: {b3d20d6a
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="261"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="156"/>
<source>Garage Door</source>
<extracomment>The name of the ThingClass ({cb206d74-b13c-4466-98c6-070b19ebd23a})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="264"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="159"/>
<source>Gateway Id</source>
<extracomment>The name of the ParamType (ThingClass: gateway, Type: thing, ID: {e321a7d6-6dcb-4a37-baf1-c7008f2d5bdb})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="267"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="165"/>
<source>Light</source>
<extracomment>The name of the ThingClass ({e569a3cc-6e79-4e24-af35-c5fa327a7314})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="270"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="273"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="168"/>
<source>Logged in</source>
<extracomment>The name of the ParamType (ThingClass: tahoma, EventType: loggedIn, ID: {97fefa85-db79-4efd-8d83-4a15d72996e1})
----------
The name of the StateType ({97fefa85-db79-4efd-8d83-4a15d72996e1}) of ThingClass tahoma</extracomment>
<extracomment>The name of the StateType ({97fefa85-db79-4efd-8d83-4a15d72996e1}) of ThingClass tahoma</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="276"/>
<source>Login state changed</source>
<extracomment>The name of the EventType ({97fefa85-db79-4efd-8d83-4a15d72996e1}) of ThingClass tahoma</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="279"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="282"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="285"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="288"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="291"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="294"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="297"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="300"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="171"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="174"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="177"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="180"/>
<source>Moving</source>
<extracomment>The name of the ParamType (ThingClass: awning, EventType: moving, ID: {2507ac5a-9658-42cb-80f6-73f673c32771})
----------
The name of the StateType ({2507ac5a-9658-42cb-80f6-73f673c32771}) of ThingClass awning
----------
The name of the ParamType (ThingClass: garagedoor, EventType: moving, ID: {07175175-f95d-4cd9-a398-9aab8232c2a9})
<extracomment>The name of the StateType ({2507ac5a-9658-42cb-80f6-73f673c32771}) of ThingClass awning
----------
The name of the StateType ({07175175-f95d-4cd9-a398-9aab8232c2a9}) of ThingClass garagedoor
----------
The name of the ParamType (ThingClass: venetianblind, EventType: moving, ID: {48d5de0a-11ab-4801-94e4-a1dd458c341d})
----------
The name of the StateType ({48d5de0a-11ab-4801-94e4-a1dd458c341d}) of ThingClass venetianblind
----------
The name of the ParamType (ThingClass: rollershutter, EventType: moving, ID: {fa9446ba-da30-4d49-8fb6-f410ecc7dba0})
----------
The name of the StateType ({fa9446ba-da30-4d49-8fb6-f410ecc7dba0}) of ThingClass rollershutter</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="303"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="306"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="309"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="312"/>
<source>Moving changed</source>
<extracomment>The name of the EventType ({2507ac5a-9658-42cb-80f6-73f673c32771}) of ThingClass awning
----------
The name of the EventType ({07175175-f95d-4cd9-a398-9aab8232c2a9}) of ThingClass garagedoor
----------
The name of the EventType ({48d5de0a-11ab-4801-94e4-a1dd458c341d}) of ThingClass venetianblind
----------
The name of the EventType ({fa9446ba-da30-4d49-8fb6-f410ecc7dba0}) of ThingClass rollershutter</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="315"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="318"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="321"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="324"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="183"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="186"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="189"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="192"/>
<source>Open</source>
<extracomment>The name of the ActionType ({9612954c-02cb-4159-9a29-f36eaf1c7f6a}) of ThingClass awning
----------
@ -252,100 +172,70 @@ The name of the ActionType ({a0460180-e799-4bc6-83ba-11731ef124a3}) of ThingClas
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="327"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="330"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="333"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="336"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="339"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="342"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="345"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="348"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="351"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="354"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="357"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="360"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="195"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="198"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="201"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="204"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="207"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="210"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="213"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="216"/>
<source>Percentage</source>
<extracomment>The name of the ParamType (ThingClass: awning, ActionType: percentage, ID: {c409cb9b-82ef-4f59-ae89-eb783d4ebe97})
----------
The name of the ParamType (ThingClass: awning, EventType: percentage, ID: {c409cb9b-82ef-4f59-ae89-eb783d4ebe97})
----------
The name of the StateType ({c409cb9b-82ef-4f59-ae89-eb783d4ebe97}) of ThingClass awning
----------
The name of the ParamType (ThingClass: garagedoor, ActionType: percentage, ID: {284816aa-842b-4a86-bb4e-ef5353b76762})
----------
The name of the ParamType (ThingClass: garagedoor, EventType: percentage, ID: {284816aa-842b-4a86-bb4e-ef5353b76762})
----------
The name of the StateType ({284816aa-842b-4a86-bb4e-ef5353b76762}) of ThingClass garagedoor
----------
The name of the ParamType (ThingClass: venetianblind, ActionType: percentage, ID: {77ca50db-42a7-4434-83e2-8b5fc4438924})
----------
The name of the ParamType (ThingClass: venetianblind, EventType: percentage, ID: {77ca50db-42a7-4434-83e2-8b5fc4438924})
----------
The name of the StateType ({77ca50db-42a7-4434-83e2-8b5fc4438924}) of ThingClass venetianblind
----------
The name of the ParamType (ThingClass: rollershutter, ActionType: percentage, ID: {f954ffc7-a6aa-4d30-aee0-0484631c3344})
----------
The name of the ParamType (ThingClass: rollershutter, EventType: percentage, ID: {f954ffc7-a6aa-4d30-aee0-0484631c3344})
----------
The name of the StateType ({f954ffc7-a6aa-4d30-aee0-0484631c3344}) of ThingClass rollershutter</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="363"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="366"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="369"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="372"/>
<source>Percentage changed</source>
<extracomment>The name of the EventType ({c409cb9b-82ef-4f59-ae89-eb783d4ebe97}) of ThingClass awning
----------
The name of the EventType ({284816aa-842b-4a86-bb4e-ef5353b76762}) of ThingClass garagedoor
----------
The name of the EventType ({77ca50db-42a7-4434-83e2-8b5fc4438924}) of ThingClass venetianblind
----------
The name of the EventType ({f954ffc7-a6aa-4d30-aee0-0484631c3344}) of ThingClass rollershutter</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="375"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="378"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="381"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="219"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="222"/>
<source>Power</source>
<extracomment>The name of the ParamType (ThingClass: light, ActionType: power, ID: {654ddcdf-b0b7-4c38-a70d-878f0f3857a5})
----------
The name of the ParamType (ThingClass: light, EventType: power, ID: {654ddcdf-b0b7-4c38-a70d-878f0f3857a5})
----------
The name of the StateType ({654ddcdf-b0b7-4c38-a70d-878f0f3857a5}) of ThingClass light</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="384"/>
<source>Power changed</source>
<extracomment>The name of the EventType ({654ddcdf-b0b7-4c38-a70d-878f0f3857a5}) of ThingClass light</extracomment>
<location filename="../../build/somfytahoma/plugininfo.h" line="162"/>
<source>Gateway pin</source>
<extracomment>The name of the ParamType (ThingClass: gateway, Type: thing, ID: {30b73244-e5bb-4c00-9332-702a60c03420})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="387"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="225"/>
<source>Roller Shutter</source>
<extracomment>The name of the ThingClass ({6b187fe0-a987-462d-90ac-c48efc0d0fc0})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="390"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="228"/>
<source>Set angle</source>
<extracomment>The name of the ActionType ({079c7a80-8a1c-4fd7-b40c-6800120c70fb}) of ThingClass venetianblind</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="393"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="231"/>
<source>Set brightness</source>
<extracomment>The name of the ActionType ({1b51ce68-1f7e-4f06-b68d-bfca2d61b353}) of ThingClass light</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="396"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="399"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="402"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="405"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="234"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="237"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="240"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="243"/>
<source>Set percentage</source>
<extracomment>The name of the ActionType ({c409cb9b-82ef-4f59-ae89-eb783d4ebe97}) of ThingClass awning
----------
@ -357,94 +247,52 @@ The name of the ActionType ({f954ffc7-a6aa-4d30-aee0-0484631c3344}) of ThingClas
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="408"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="246"/>
<source>Set power</source>
<extracomment>The name of the ActionType ({654ddcdf-b0b7-4c38-a70d-878f0f3857a5}) of ThingClass light</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="411"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="414"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="417"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="420"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="423"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="426"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="429"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="432"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="435"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="438"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="249"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="252"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="255"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="258"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="261"/>
<source>Signal strength</source>
<extracomment>The name of the ParamType (ThingClass: light, EventType: signalStrength, ID: {cfaa5533-d26e-4545-9f44-6567c9d7888a})
----------
The name of the StateType ({cfaa5533-d26e-4545-9f44-6567c9d7888a}) of ThingClass light
----------
The name of the ParamType (ThingClass: awning, EventType: signalStrength, ID: {b2ad6f4a-c507-45c3-a951-b344603cc3fc})
<extracomment>The name of the StateType ({cfaa5533-d26e-4545-9f44-6567c9d7888a}) of ThingClass light
----------
The name of the StateType ({b2ad6f4a-c507-45c3-a951-b344603cc3fc}) of ThingClass awning
----------
The name of the ParamType (ThingClass: garagedoor, EventType: signalStrength, ID: {0a194091-3073-4912-9d84-f1d52c8534bd})
----------
The name of the StateType ({0a194091-3073-4912-9d84-f1d52c8534bd}) of ThingClass garagedoor
----------
The name of the ParamType (ThingClass: venetianblind, EventType: signalStrength, ID: {aee4f4e3-3445-441d-bdbb-631b0c5db942})
----------
The name of the StateType ({aee4f4e3-3445-441d-bdbb-631b0c5db942}) of ThingClass venetianblind
----------
The name of the ParamType (ThingClass: rollershutter, EventType: signalStrength, ID: {67594d96-47a2-4360-a1b8-79e4f22f9ed0})
----------
The name of the StateType ({67594d96-47a2-4360-a1b8-79e4f22f9ed0}) of ThingClass rollershutter</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="441"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="444"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="447"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="450"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="453"/>
<source>Signal strength changed</source>
<extracomment>The name of the EventType ({cfaa5533-d26e-4545-9f44-6567c9d7888a}) of ThingClass light
----------
The name of the EventType ({b2ad6f4a-c507-45c3-a951-b344603cc3fc}) of ThingClass awning
----------
The name of the EventType ({0a194091-3073-4912-9d84-f1d52c8534bd}) of ThingClass garagedoor
----------
The name of the EventType ({aee4f4e3-3445-441d-bdbb-631b0c5db942}) of ThingClass venetianblind
----------
The name of the EventType ({67594d96-47a2-4360-a1b8-79e4f22f9ed0}) of ThingClass rollershutter</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="456"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="264"/>
<source>Somfy</source>
<extracomment>The name of the vendor ({4e42a22a-ccfb-4677-89e3-f7fa16bf6be0})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="459"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="267"/>
<source>Somfy Tahoma</source>
<extracomment>The name of the plugin SomfyTahoma ({4e8be1c1-daa8-4e21-9e85-b2372ab1a450})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="462"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="465"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="270"/>
<source>State</source>
<extracomment>The name of the ParamType (ThingClass: garagedoor, EventType: state, ID: {12af28f1-475e-4d05-9bbb-adbb86dcd69c})
----------
The name of the StateType ({12af28f1-475e-4d05-9bbb-adbb86dcd69c}) of ThingClass garagedoor</extracomment>
<extracomment>The name of the StateType ({12af28f1-475e-4d05-9bbb-adbb86dcd69c}) of ThingClass garagedoor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="468"/>
<source>State changed</source>
<extracomment>The name of the EventType ({12af28f1-475e-4d05-9bbb-adbb86dcd69c}) of ThingClass garagedoor</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="471"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="474"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="477"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="480"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="273"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="276"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="279"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="282"/>
<source>Stop</source>
<extracomment>The name of the ActionType ({33bec73b-4d15-493a-b553-bcee32c40ee1}) of ThingClass awning
----------
@ -456,34 +304,25 @@ The name of the ActionType ({cbccf714-1188-4ac9-9c91-17fe2c99acb3}) of ThingClas
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="483"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="285"/>
<source>Tahoma Account</source>
<extracomment>The name of the ThingClass ({fedd72b8-547d-4e4f-b73e-71344a8ba0c1})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="486"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="288"/>
<source>Tahoma Gateway</source>
<extracomment>The name of the ThingClass ({6c09e0b9-f0cc-4dea-9994-9e039eff78f1})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="489"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="492"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="291"/>
<source>User display name</source>
<extracomment>The name of the ParamType (ThingClass: tahoma, EventType: userDisplayName, ID: {75609987-be60-4932-94f6-ead791b5fa58})
----------
The name of the StateType ({75609987-be60-4932-94f6-ead791b5fa58}) of ThingClass tahoma</extracomment>
<extracomment>The name of the StateType ({75609987-be60-4932-94f6-ead791b5fa58}) of ThingClass tahoma</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="495"/>
<source>User display name changed</source>
<extracomment>The name of the EventType ({75609987-be60-4932-94f6-ead791b5fa58}) of ThingClass tahoma</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../build/somfytahoma/plugininfo.h" line="498"/>
<location filename="../../build/somfytahoma/plugininfo.h" line="294"/>
<source>Venetian Blind</source>
<extracomment>The name of the ThingClass ({c7160205-d864-4194-b418-060fff60f0cb})</extracomment>
<translation type="unfinished"></translation>