From e69408f655d9dcc74dae8c536379b6c9e2227412 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sun, 17 Sep 2023 17:57:38 +0200 Subject: [PATCH] Generic shading: Add generic awning with position control --- .../integrationplugingenericshading.cpp | 118 ++++++++++++++++++ .../integrationplugingenericshading.h | 2 + .../integrationplugingenericshading.json | 92 ++++++++++++++ 3 files changed, 212 insertions(+) diff --git a/genericshading/integrationplugingenericshading.cpp b/genericshading/integrationplugingenericshading.cpp index a35319b..126c449 100644 --- a/genericshading/integrationplugingenericshading.cpp +++ b/genericshading/integrationplugingenericshading.cpp @@ -86,6 +86,49 @@ void IntegrationPluginGenericShading::setupThing(ThingSetupInfo *info) } } }); + } 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(); @@ -230,6 +273,40 @@ void IntegrationPluginGenericShading::executeAction(ThingActionInfo *info) } 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"); @@ -433,6 +510,31 @@ void IntegrationPluginGenericShading::setBlindState(IntegrationPluginGenericShad 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) { @@ -481,6 +583,22 @@ void IntegrationPluginGenericShading::moveBlindToPercentage(Action action, Thing } 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(); diff --git a/genericshading/integrationplugingenericshading.h b/genericshading/integrationplugingenericshading.h index f923735..e681cd5 100644 --- a/genericshading/integrationplugingenericshading.h +++ b/genericshading/integrationplugingenericshading.h @@ -54,8 +54,10 @@ private: double mapDoubleValue(double value, double fromMin, double fromMax, double toMin, double toMax); QHash m_extendedBlindPercentageTimer; + QHash m_extendedAwningPercentageTimer; QHash m_venetianBlindAngleTimer; QHash m_extendedBlindTargetPercentage; + QHash m_extendedAwningTargetPercentage; QHash m_venetianBlindTargetAngle; enum BlindState { diff --git a/genericshading/integrationplugingenericshading.json b/genericshading/integrationplugingenericshading.json index 4c0031f..90dc8d1 100644 --- a/genericshading/integrationplugingenericshading.json +++ b/genericshading/integrationplugingenericshading.json @@ -69,6 +69,98 @@ } ] }, + { + "id": "be9ffcc5-28b9-4db9-aaec-d6e758776a60", + "name": "extendedAwning", + "displayName": "Generic awning with position control", + "createMethods": ["user"], + "interfaces": ["extendedawning"], + "settingsTypes": [ + { + "id": "8f1d651d-3196-48c7-b752-9d906c44168c", + "name": "closingDuration", + "displayName": "Closing duration [ms]", + "type": "uint", + "minValue": 1000, + "defaultValue": 5000 + } + ], + "stateTypes": [ + { + "id": "43c174e2-31d2-4256-a81f-09997ec1c0a3", + "name": "openingOutput", + "displayName": "Opening output", + "displayNameEvent": "Opening output changed", + "displayNameAction": "Set opening output", + "type": "bool", + "defaultValue": false, + "ioType": "digitalInput", + "writable": true + }, + { + "id": "4992092c-d765-4764-a3d5-658171a74093", + "name": "closingOutput", + "displayName": "Closing output", + "displayNameEvent": "Closing output changed", + "displayNameAction": "Set closing output", + "type": "bool", + "defaultValue": false, + "ioType": "digitalInput", + "writable": true + }, + { + "id": "c24f6229-91df-4ca5-8555-d6d5d948062c", + "name": "status", + "displayName": "Status", + "displayNameEvent": "Status changed", + "type": "QString", + "possibleValues": [ + "Opening", + "Stopped", + "Closing" + ], + "defaultValue": "Stopped" + }, + { + "id": "010d3f47-7c05-4e71-a2f9-3f53958e8095", + "name": "moving", + "type": "bool", + "displayName": "Moving", + "displayNameEvent": "Moving changed", + "defaultValue": false + }, + { + "id": "ce82e5d1-dbb8-4916-a966-a2ab85e4cda7", + "name": "percentage", + "displayName": "Percentage", + "displayNameEvent": "Percentage changed", + "displayNameAction": "Set percentage", + "type": "int", + "minValue": 0, + "maxValue": 100, + "defaultValue": 0, + "unit": "Percentage", + "writable": true + } + ], + "actionTypes": [ + { + "id": "4ee66b18-0c2b-4578-9ae1-34d816e84563", + "name": "open", + "displayName": "Open" + }, + { + "id": "48ae5686-7bd6-4f10-a6a4-2ac502aafa5f", + "name": "stop", + "displayName": "Stop" + }, + { + "id": "6e71e4a1-af8b-4a93-a66c-ef1782e03621", + "name": "close", + "displayName": "Close" + } + ] + }, { "id": "17ee3657-6ad8-4ae2-8959-3cf66cec8d13", "name": "blind",