// SPDX-License-Identifier: GPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of nymea-plugins-genericthings. * * nymea-plugins-genericthings is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * nymea-plugins-genericthings is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with nymea-plugins-genericthings. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "integrationplugingenericshading.h" #include "plugininfo.h" #include IntegrationPluginGenericShading::IntegrationPluginGenericShading() { } void IntegrationPluginGenericShading::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); if (thing->thingClassId() == extendedBlindThingClassId) { uint closingDuration = thing->setting(extendedBlindSettingsClosingDurationParamTypeId).toUInt(); QTimer* timer = new QTimer(this); timer->setInterval(closingDuration/100.00); // closing timer / 100 to update on every percent m_extendedBlindPercentageTimer.insert(thing, timer); connect(thing, &Thing::settingChanged, thing, [timer] (const ParamTypeId ¶mTypeId, const QVariant &value) { if (paramTypeId == extendedBlindSettingsClosingDurationParamTypeId) { timer->setInterval(value.toUInt()/100.00); } }); connect(timer, &QTimer::timeout, this, [thing, this] { uint currentPercentage = thing->stateValue(extendedBlindPercentageStateTypeId).toUInt(); if (thing->stateValue(extendedBlindStatusStateTypeId).toString() == "Closing") { if (currentPercentage == 100) { setBlindState(BlindStateStopped, thing); qCDebug(dcGenericShading()) << "Extended blind is closed, stopping timer"; } else { currentPercentage++; thing->setStateValue(extendedBlindPercentageStateTypeId, currentPercentage); } } else if (thing->stateValue(extendedBlindStatusStateTypeId).toString() == "Opening") { if (currentPercentage == 0) { setBlindState(BlindStateStopped, thing); qCDebug(dcGenericShading()) << "Extended blind is opened, stopping timer"; } else { currentPercentage--; thing->setStateValue(extendedBlindPercentageStateTypeId, currentPercentage); } } else { setBlindState(BlindStateStopped, thing); } if (m_extendedBlindPercentageTimer.contains(thing)) { uint targetPercentage = m_extendedBlindTargetPercentage.value(thing); if (targetPercentage == currentPercentage) { qCDebug(dcGenericShading()) << "Extended blind has reached target percentage, stopping timer"; setBlindState(BlindStateStopped, thing); } } }); } else if (thing->thingClassId() == extendedAwningThingClassId) { uint closingDuration = thing->setting(extendedAwningSettingsClosingDurationParamTypeId).toUInt(); QTimer* timer = new QTimer(this); timer->setInterval(closingDuration/100.00); // closing timer / 100 to update on every percent m_extendedAwningPercentageTimer.insert(thing, timer); connect(thing, &Thing::settingChanged, thing, [timer] (const ParamTypeId ¶mTypeId, const QVariant &value) { if (paramTypeId == extendedAwningSettingsClosingDurationParamTypeId) { timer->setInterval(value.toUInt()/100.00); } }); connect(timer, &QTimer::timeout, this, [thing, this] { uint currentPercentage = thing->stateValue(extendedAwningPercentageStateTypeId).toUInt(); if (thing->stateValue(extendedAwningStatusStateTypeId).toString() == "Closing") { if (currentPercentage == 100) { setBlindState(BlindStateStopped, thing); qCDebug(dcGenericShading()) << "Extended awning is closed, stopping timer"; } else { currentPercentage++; thing->setStateValue(extendedAwningPercentageStateTypeId, currentPercentage); } } else if (thing->stateValue(extendedAwningStatusStateTypeId).toString() == "Opening") { if (currentPercentage == 0) { setBlindState(BlindStateStopped, thing); qCDebug(dcGenericShading()) << "Extended awning is opened, stopping timer"; } else { currentPercentage--; thing->setStateValue(extendedAwningPercentageStateTypeId, currentPercentage); } } else { setBlindState(BlindStateStopped, thing); } if (m_extendedAwningPercentageTimer.contains(thing)) { uint targetPercentage = m_extendedAwningTargetPercentage.value(thing); if (targetPercentage == currentPercentage) { qCDebug(dcGenericShading()) << "Extended awning has reached target percentage, stopping timer"; setBlindState(BlindStateStopped, thing); } } }); } else if (info->thing()->thingClassId() == venetianBlindThingClassId) { uint closingTime = thing->setting(venetianBlindSettingsClosingDurationParamTypeId).toUInt(); uint angleTime = thing->setting(venetianBlindSettingsAngleTimeParamTypeId).toUInt(); if (closingTime < angleTime) { return info->finish(Thing::ThingErrorSetupFailed, tr("Invalid closing or angle time")); } QTimer* closingTimer = new QTimer(this); closingTimer->setInterval(closingTime/100.00); // closing timer / 100 to update on every percent m_extendedBlindPercentageTimer.insert(thing, closingTimer); connect(closingTimer, &QTimer::timeout, thing, [thing, this] { uint currentPercentage = thing->stateValue(venetianBlindPercentageStateTypeId).toUInt(); if (thing->stateValue(venetianBlindStatusStateTypeId).toString() == "Closing") { if (currentPercentage == 100) { setBlindState(BlindStateStopped, thing); qCDebug(dcGenericShading()) << "Venetian blind is closed, stopping timer"; } else if (currentPercentage > 100) { currentPercentage = 100; setBlindState(BlindStateStopped, thing); qCWarning(dcGenericShading()) << "Venetian blind overshoot 100 percent"; } else { currentPercentage++; thing->setStateValue(venetianBlindPercentageStateTypeId, currentPercentage); } } else if (thing->stateValue(venetianBlindStatusStateTypeId).toString() == "Opening") { if (currentPercentage == 0) { setBlindState(BlindStateStopped, thing); qCDebug(dcGenericShading()) << "Venetian blind is opened, stopping timer"; } else { currentPercentage--; thing->setStateValue(venetianBlindPercentageStateTypeId, currentPercentage); } } else { setBlindState(BlindStateStopped, thing); } if (m_extendedBlindPercentageTimer.contains(thing)) { uint targetPercentage = m_extendedBlindTargetPercentage.value(thing); if (targetPercentage == currentPercentage) { qCDebug(dcGenericShading()) << "Venetian blind has reached target percentage, stopping timer"; setBlindState(BlindStateStopped, thing); } } }); QTimer* angleTimer = new QTimer(this); angleTimer->setInterval(angleTime/180.00); // -90 to 90 degree -> 180 degree total m_venetianBlindAngleTimer.insert(thing, angleTimer); connect(thing, &Thing::settingChanged, thing, [closingTimer, angleTimer] (const ParamTypeId ¶mTypeId, const QVariant &value) { if (paramTypeId == venetianBlindSettingsClosingDurationParamTypeId) { closingTimer->setInterval(value.toUInt()/100.00); } else if (paramTypeId == venetianBlindSettingsAngleTimeParamTypeId) { angleTimer->setInterval(value.toUInt()/180.00); } }); connect(angleTimer, &QTimer::timeout, thing, [thing, this] { int currentAngle = thing->stateValue(venetianBlindAngleStateTypeId).toInt(); if (thing->stateValue(venetianBlindStatusStateTypeId).toString() == "Closing") { if (currentAngle < 90) { currentAngle++; } else if (currentAngle == 90) { m_venetianBlindAngleTimer.value(thing)->stop(); } else if (currentAngle > 90) { currentAngle = 90; m_venetianBlindAngleTimer.value(thing)->stop(); qCWarning(dcGenericShading()) << "Venetian blind overshoot angle boundaries"; } thing->setStateValue(venetianBlindAngleStateTypeId, currentAngle); } else if (thing->stateValue(venetianBlindStatusStateTypeId).toString() == "Opening") { if (currentAngle > -90) { currentAngle--; } else if (currentAngle == -90) { m_venetianBlindAngleTimer.value(thing)->stop(); } else if (currentAngle < -90) { currentAngle = -90; m_venetianBlindAngleTimer.value(thing)->stop(); qCWarning(dcGenericShading()) << "Venetian blind overshoot angle boundaries"; } thing->setStateValue(venetianBlindAngleStateTypeId, currentAngle); } if (m_venetianBlindTargetAngle.contains(thing)) { int targetAngle = m_venetianBlindTargetAngle.value(thing); if (targetAngle == currentAngle) { qCDebug(dcGenericShading()) << "Venetian blind has reached target angle, stopping timer"; setBlindState(BlindStateStopped, thing); } } }); } // Fall trough, if not already finished and returned... info->finish(Thing::ThingErrorNoError); } void IntegrationPluginGenericShading::executeAction(ThingActionInfo *info) { Thing *thing = info->thing(); Action action = info->action(); if (thing->thingClassId() == awningThingClassId) { if (action.actionTypeId() == awningOpenActionTypeId) { thing->setStateValue(awningStatusStateTypeId, "Opening"); thing->setStateValue(awningClosingOutputStateTypeId, false); thing->setStateValue(awningOpeningOutputStateTypeId, true); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == awningStopActionTypeId) { thing->setStateValue(awningStatusStateTypeId, "Stopped"); thing->setStateValue(awningOpeningOutputStateTypeId, false); thing->setStateValue(awningClosingOutputStateTypeId, false); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == awningCloseActionTypeId) { thing->setStateValue(awningStatusStateTypeId, "Closing"); thing->setStateValue(awningOpeningOutputStateTypeId, false); thing->setStateValue(awningClosingOutputStateTypeId, true); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == awningOpeningOutputActionTypeId) { bool on = action.param(awningOpeningOutputActionOpeningOutputParamTypeId).value().toBool(); thing->setStateValue(awningOpeningOutputStateTypeId, on); if (on) { thing->setStateValue(awningStatusStateTypeId, "Opening"); thing->setStateValue(awningClosingOutputStateTypeId, false); } else { thing->setStateValue(awningStatusStateTypeId, "Stopped"); } info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == awningClosingOutputActionTypeId) { bool on = action.param(awningClosingOutputActionClosingOutputParamTypeId).value().toBool(); thing->setStateValue(awningClosingOutputStateTypeId, on); if (on) { thing->setStateValue(awningStatusStateTypeId, "Closing"); thing->setStateValue(awningOpeningOutputStateTypeId, false); } else { thing->setStateValue(awningStatusStateTypeId, "Stopped"); } info->finish(Thing::ThingErrorNoError); } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } } else if (thing->thingClassId() == extendedAwningThingClassId) { if (action.actionTypeId() == extendedAwningOpenActionTypeId) { setBlindState(BlindStateOpening, thing); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedAwningStopActionTypeId) { setBlindState(BlindStateStopped, thing); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedAwningCloseActionTypeId) { setBlindState(BlindStateClosing, thing); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedAwningOpeningOutputActionTypeId) { bool on = action.param(extendedAwningOpeningOutputActionOpeningOutputParamTypeId).value().toBool(); thing->setStateValue(extendedAwningOpeningOutputStateTypeId, on); if (on) { setBlindState(BlindStateOpening, thing); } else { setBlindState(BlindStateStopped, thing); } info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedAwningClosingOutputActionTypeId) { bool on = action.param(extendedAwningClosingOutputActionClosingOutputParamTypeId).value().toBool(); thing->setStateValue(extendedAwningClosingOutputStateTypeId, on); if (on) { setBlindState(BlindStateClosing, thing); } else { setBlindState(BlindStateStopped, thing); } info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedAwningPercentageActionTypeId) { moveBlindToPercentage(action, thing); } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } } else if (thing->thingClassId() == blindThingClassId ) { if (action.actionTypeId() == blindOpenActionTypeId) { thing->setStateValue(blindStatusStateTypeId, "Opening"); thing->setStateValue(blindClosingOutputStateTypeId, false); thing->setStateValue(blindOpeningOutputStateTypeId, true); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == blindStopActionTypeId) { thing->setStateValue(blindStatusStateTypeId, "Stopped"); thing->setStateValue(blindOpeningOutputStateTypeId, false); thing->setStateValue(blindClosingOutputStateTypeId, false); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == blindCloseActionTypeId) { thing->setStateValue(blindStatusStateTypeId, "Closing"); thing->setStateValue(blindOpeningOutputStateTypeId, false); thing->setStateValue(blindClosingOutputStateTypeId, true); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == blindOpeningOutputActionTypeId) { bool on = action.param(blindOpeningOutputActionOpeningOutputParamTypeId).value().toBool(); thing->setStateValue(blindOpeningOutputStateTypeId, on); if (on) { thing->setStateValue(blindStatusStateTypeId, "Opening"); thing->setStateValue(blindClosingOutputStateTypeId, false); } else { thing->setStateValue(blindStatusStateTypeId, "Stopped"); } info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == blindClosingOutputActionTypeId) { bool on = action.param(blindClosingOutputActionClosingOutputParamTypeId).value().toBool(); thing->setStateValue(blindClosingOutputStateTypeId, on); if (on) { thing->setStateValue(blindStatusStateTypeId, "Closing"); thing->setStateValue(blindOpeningOutputStateTypeId, false); } else { thing->setStateValue(blindStatusStateTypeId, "Stopped"); } info->finish(Thing::ThingErrorNoError); } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } } else if (thing->thingClassId() == extendedBlindThingClassId) { if (action.actionTypeId() == extendedBlindOpenActionTypeId) { setBlindState(BlindStateOpening, thing); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedBlindStopActionTypeId) { setBlindState(BlindStateStopped, thing); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedBlindCloseActionTypeId) { setBlindState(BlindStateClosing, thing); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedBlindOpeningOutputActionTypeId) { bool on = action.param(extendedBlindOpeningOutputActionOpeningOutputParamTypeId).value().toBool(); thing->setStateValue(extendedBlindOpeningOutputStateTypeId, on); if (on) { setBlindState(BlindStateOpening, thing); } else { setBlindState(BlindStateStopped, thing); } info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedBlindClosingOutputActionTypeId) { bool on = action.param(extendedBlindClosingOutputActionClosingOutputParamTypeId).value().toBool(); thing->setStateValue(extendedBlindClosingOutputStateTypeId, on); if (on) { setBlindState(BlindStateClosing, thing); } else { setBlindState(BlindStateStopped, thing); } info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == extendedBlindPercentageActionTypeId) { moveBlindToPercentage(action, thing); } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } } else if (thing->thingClassId() == venetianBlindThingClassId) { if (action.actionTypeId() == venetianBlindOpenActionTypeId) { setBlindState(BlindStateOpening, thing); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == venetianBlindStopActionTypeId) { setBlindState(BlindStateStopped, thing); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == venetianBlindCloseActionTypeId) { setBlindState(BlindStateClosing, thing); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == venetianBlindOpeningOutputActionTypeId) { bool on = action.param(venetianBlindOpeningOutputActionOpeningOutputParamTypeId).value().toBool(); thing->setStateValue(venetianBlindOpeningOutputStateTypeId, on); if (on) { setBlindState(BlindStateOpening, thing); } else { setBlindState(BlindStateStopped, thing); } info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == venetianBlindClosingOutputActionTypeId) { bool on = action.param(venetianBlindClosingOutputActionClosingOutputParamTypeId).value().toBool(); thing->setStateValue(venetianBlindClosingOutputStateTypeId, on); if (on) { setBlindState(BlindStateClosing, thing); } else { setBlindState(BlindStateStopped, thing); } info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == venetianBlindPercentageActionTypeId) { moveBlindToPercentage(action, thing); info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == venetianBlindAngleActionTypeId) { moveBlindToAngle(action, thing); info->finish(Thing::ThingErrorNoError); } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } } else if (thing->thingClassId() == shutterThingClassId) { if (action.actionTypeId() == shutterOpenActionTypeId) { thing->setStateValue(shutterStatusStateTypeId, "Opening"); thing->setStateValue(shutterClosingOutputStateTypeId, false); thing->setStateValue(shutterOpeningOutputStateTypeId, true); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == shutterStopActionTypeId) { thing->setStateValue(shutterStatusStateTypeId, "Stopped"); thing->setStateValue(shutterOpeningOutputStateTypeId, false); thing->setStateValue(shutterClosingOutputStateTypeId, false); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == shutterCloseActionTypeId) { thing->setStateValue(shutterStatusStateTypeId, "Closing"); thing->setStateValue(shutterOpeningOutputStateTypeId, false); thing->setStateValue(shutterClosingOutputStateTypeId, true); return info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == shutterOpeningOutputActionTypeId) { bool on = action.param(shutterOpeningOutputActionOpeningOutputParamTypeId).value().toBool(); thing->setStateValue(shutterOpeningOutputStateTypeId, on); if (on) { thing->setStateValue(shutterStatusStateTypeId, "Opening"); thing->setStateValue(shutterClosingOutputStateTypeId, false); } else { thing->setStateValue(shutterStatusStateTypeId, "Stopped"); } info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == shutterClosingOutputActionTypeId) { bool on = action.param(shutterClosingOutputActionClosingOutputParamTypeId).value().toBool(); thing->setStateValue(shutterClosingOutputStateTypeId, on); if (on) { thing->setStateValue(shutterStatusStateTypeId, "Closing"); thing->setStateValue(shutterOpeningOutputStateTypeId, false); } else { thing->setStateValue(shutterStatusStateTypeId, "Stopped"); } info->finish(Thing::ThingErrorNoError); } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); } } void IntegrationPluginGenericShading::thingRemoved(Thing *thing) { if (thing->thingClassId() == extendedBlindThingClassId) { m_extendedBlindPercentageTimer.take(thing)->deleteLater(); m_extendedBlindTargetPercentage.remove(thing); } else if (thing->thingClassId() == venetianBlindThingClassId) { m_extendedBlindPercentageTimer.take(thing)->deleteLater(); m_extendedBlindTargetPercentage.remove(thing); m_venetianBlindAngleTimer.take(thing)->deleteLater(); m_venetianBlindTargetAngle.remove(thing); } } double IntegrationPluginGenericShading::mapDoubleValue(double value, double fromMin, double fromMax, double toMin, double toMax) { double percent = (value - fromMin) / (fromMax - fromMin); double toValue = toMin + (toMax - toMin) * percent; return toValue; } void IntegrationPluginGenericShading::setBlindState(IntegrationPluginGenericShading::BlindState state, Thing *thing) { //If an ongoing "to percentage" actions is beeing executed, it is now overruled by another action m_extendedBlindTargetPercentage.remove(thing); if (thing->thingClassId() == extendedBlindThingClassId) { switch (state) { case BlindStateOpening: thing->setStateValue(extendedBlindStatusStateTypeId, "Opening"); thing->setStateValue(extendedBlindClosingOutputStateTypeId, false); thing->setStateValue(extendedBlindOpeningOutputStateTypeId, true); thing->setStateValue(extendedBlindMovingStateTypeId, true); m_extendedBlindPercentageTimer.value(thing)->start(); break; case BlindStateClosing: thing->setStateValue(extendedBlindStatusStateTypeId, "Closing"); thing->setStateValue(extendedBlindClosingOutputStateTypeId, true); thing->setStateValue(extendedBlindOpeningOutputStateTypeId, false); thing->setStateValue(extendedBlindMovingStateTypeId, true); m_extendedBlindPercentageTimer.value(thing)->start(); break; case BlindStateStopped: thing->setStateValue(extendedBlindStatusStateTypeId, "Stopped"); thing->setStateValue(extendedBlindClosingOutputStateTypeId, false); thing->setStateValue(extendedBlindOpeningOutputStateTypeId, false); thing->setStateValue(extendedBlindMovingStateTypeId, false); m_extendedBlindPercentageTimer.value(thing)->stop(); break; } } else if (thing->thingClassId() == extendedAwningThingClassId) { switch (state) { case BlindStateOpening: thing->setStateValue(extendedAwningStatusStateTypeId, "Opening"); thing->setStateValue(extendedAwningClosingOutputStateTypeId, false); thing->setStateValue(extendedAwningOpeningOutputStateTypeId, true); thing->setStateValue(extendedAwningMovingStateTypeId, true); m_extendedAwningPercentageTimer.value(thing)->start(); break; case BlindStateClosing: thing->setStateValue(extendedAwningStatusStateTypeId, "Closing"); thing->setStateValue(extendedAwningClosingOutputStateTypeId, true); thing->setStateValue(extendedAwningOpeningOutputStateTypeId, false); thing->setStateValue(extendedAwningMovingStateTypeId, true); m_extendedAwningPercentageTimer.value(thing)->start(); break; case BlindStateStopped: thing->setStateValue(extendedAwningStatusStateTypeId, "Stopped"); thing->setStateValue(extendedAwningClosingOutputStateTypeId, false); thing->setStateValue(extendedAwningOpeningOutputStateTypeId, false); thing->setStateValue(extendedAwningMovingStateTypeId, false); m_extendedAwningPercentageTimer.value(thing)->stop(); break; } } else if (thing->thingClassId() == venetianBlindThingClassId) { m_venetianBlindTargetAngle.remove(thing); switch (state) { case BlindStateOpening: thing->setStateValue(venetianBlindStatusStateTypeId, "Opening"); thing->setStateValue(venetianBlindClosingOutputStateTypeId, false); thing->setStateValue(venetianBlindOpeningOutputStateTypeId, true); thing->setStateValue(venetianBlindMovingStateTypeId, true); m_extendedBlindPercentageTimer.value(thing)->start(); m_venetianBlindAngleTimer.value(thing)->start(); break; case BlindStateClosing: thing->setStateValue(venetianBlindStatusStateTypeId, "Closing"); thing->setStateValue(venetianBlindClosingOutputStateTypeId, true); thing->setStateValue(venetianBlindOpeningOutputStateTypeId, false); thing->setStateValue(venetianBlindMovingStateTypeId, true); m_extendedBlindPercentageTimer.value(thing)->start(); m_venetianBlindAngleTimer.value(thing)->start(); break; case BlindStateStopped: thing->setStateValue(venetianBlindStatusStateTypeId, "Stopped"); thing->setStateValue(venetianBlindClosingOutputStateTypeId, false); thing->setStateValue(venetianBlindOpeningOutputStateTypeId, false); thing->setStateValue(venetianBlindMovingStateTypeId, false); m_extendedBlindPercentageTimer.value(thing)->stop(); m_venetianBlindAngleTimer.value(thing)->stop(); break; } } } void IntegrationPluginGenericShading::moveBlindToPercentage(Action action, Thing *thing) { if (thing->thingClassId() == extendedBlindThingClassId) { uint targetPercentage = action.param(extendedBlindPercentageActionPercentageParamTypeId).value().toUInt(); uint currentPercentage = thing->stateValue(extendedBlindPercentageStateTypeId).toUInt(); // 100% indicates the device is fully closed if (targetPercentage == currentPercentage) { qCDebug(dcGenericShading()) << "Extended blind is already at given percentage" << targetPercentage; } else if (targetPercentage > currentPercentage) { setBlindState(BlindStateClosing, thing); m_extendedBlindTargetPercentage.insert(thing, targetPercentage); } else if (targetPercentage < currentPercentage) { setBlindState(BlindStateOpening, thing); m_extendedBlindTargetPercentage.insert(thing, targetPercentage); } else { setBlindState(BlindStateStopped, thing); } } else if (thing->thingClassId() == extendedAwningThingClassId) { uint targetPercentage = action.param(extendedAwningPercentageActionPercentageParamTypeId).value().toUInt(); uint currentPercentage = thing->stateValue(extendedAwningPercentageStateTypeId).toUInt(); // 100% indicates the device is fully closed if (targetPercentage == currentPercentage) { qCDebug(dcGenericShading()) << "Extended awningis already at given percentage" << targetPercentage; } else if (targetPercentage > currentPercentage) { setBlindState(BlindStateClosing, thing); m_extendedAwningTargetPercentage.insert(thing, targetPercentage); } else if (targetPercentage < currentPercentage) { setBlindState(BlindStateOpening, thing); m_extendedAwningTargetPercentage.insert(thing, targetPercentage); } else { setBlindState(BlindStateStopped, thing); } } else if (thing->thingClassId() == venetianBlindThingClassId) { uint targetPercentage = action.param(venetianBlindPercentageActionPercentageParamTypeId).value().toUInt(); uint currentPercentage = thing->stateValue(venetianBlindPercentageStateTypeId).toUInt(); qCDebug(dcGenericShading()) << "Moving venetian blind to percentage" << targetPercentage << "Current percentage:" << currentPercentage; // 100% indicates the device is fully closed if (targetPercentage == currentPercentage) { qCDebug(dcGenericShading()) << "Extended blind is already at given percentage" << targetPercentage; } else if (targetPercentage > currentPercentage) { setBlindState(BlindStateClosing, thing); m_extendedBlindTargetPercentage.insert(thing, targetPercentage); } else if (targetPercentage < currentPercentage) { setBlindState(BlindStateOpening, thing); m_extendedBlindTargetPercentage.insert(thing, targetPercentage); } else { setBlindState(BlindStateStopped, thing); } } else { qCDebug(dcGenericShading()) << "Move to percentage doesn't support this thingClass"; } } void IntegrationPluginGenericShading::moveBlindToAngle(Action action, Thing *thing) { if (thing->thingClassId() == venetianBlindThingClassId) { if (action.actionTypeId() == venetianBlindAngleActionTypeId) { //NOTE moving percentage affects the angle but the angle doesnt affect the percentage // opening -> -90 // closing -> +90 int targetAngle = action.param(venetianBlindAngleActionAngleParamTypeId).value().toInt(); int currentAngle = thing->stateValue(venetianBlindAngleStateTypeId).toInt(); if (targetAngle == currentAngle) { qCDebug(dcGenericShading()) << "Venetian blind is already at given angle" << targetAngle; } else if (targetAngle > currentAngle) { setBlindState(BlindStateClosing, thing); m_venetianBlindTargetAngle.insert(thing, targetAngle); } else if (targetAngle < currentAngle) { setBlindState(BlindStateOpening, thing); m_venetianBlindTargetAngle.insert(thing, targetAngle); } else { setBlindState(BlindStateStopped, thing); } } } else { qCDebug(dcGenericShading()) << "Move to angle doesn't support this thingClass"; } }