From 86018b95bcf1dd97dc97e324bed294696d71184b Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 3 Aug 2020 13:39:11 +0200 Subject: [PATCH] Generic Things: Add generic garage doors --- .../integrationplugingenericthings.cpp | 106 ++++++++++- .../integrationplugingenericthings.h | 2 + .../integrationplugingenericthings.json | 177 +++++++++++++++++- 3 files changed, 269 insertions(+), 16 deletions(-) diff --git a/genericthings/integrationplugingenericthings.cpp b/genericthings/integrationplugingenericthings.cpp index 01b7487..843f2e2 100644 --- a/genericthings/integrationplugingenericthings.cpp +++ b/genericthings/integrationplugingenericthings.cpp @@ -45,15 +45,12 @@ void IntegrationPluginGenericThings::setupThing(ThingSetupInfo *info) Thing *thing = info->thing(); if (thing->thingClassId() == extendedBlindThingClassId) { - uint closingTime = thing->setting(extendedBlindSettingsClosingTimeParamTypeId).toUInt(); - if (closingTime == 0) { - return info->finish(Thing::ThingErrorSetupFailed, tr("Invalid closing time")); - } + uint closingDuration = thing->setting(extendedBlindSettingsClosingDurationParamTypeId).toUInt(); QTimer* timer = new QTimer(this); - timer->setInterval(closingTime/100.00); // closing timer / 100 to update on every percent + 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 == extendedBlindSettingsClosingTimeParamTypeId) { + if (paramTypeId == extendedBlindSettingsClosingDurationParamTypeId) { timer->setInterval(value.toUInt()/100.00); } }); @@ -91,7 +88,7 @@ void IntegrationPluginGenericThings::setupThing(ThingSetupInfo *info) } }); } else if (info->thing()->thingClassId() == venetianBlindThingClassId) { - uint closingTime = thing->setting(venetianBlindSettingsClosingTimeParamTypeId).toUInt(); + 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")); @@ -142,7 +139,7 @@ void IntegrationPluginGenericThings::setupThing(ThingSetupInfo *info) 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 == venetianBlindSettingsClosingTimeParamTypeId) { + if (paramTypeId == venetianBlindSettingsClosingDurationParamTypeId) { closingTimer->setInterval(value.toUInt()/100.00); } else if (paramTypeId == venetianBlindSettingsAngleTimeParamTypeId) { angleTimer->setInterval(value.toUInt()/180.00); @@ -204,6 +201,48 @@ void IntegrationPluginGenericThings::setupThing(ThingSetupInfo *info) thing->setStateValue(extendedSmartMeterConsumerCurrentPowerStateTypeId, power*1000); m_pulsesPerTimeframe.insert(thing, 0); }); + } else if (thing->thingClassId() == extendedStatefulGaragedoorThingClassId) { + uint openingDuration = thing->setting(extendedStatefulGaragedoorSettingsOpeningDurationParamTypeId).toUInt(); + QTimer* timer = new QTimer(this); + timer->setInterval(openingDuration/100.00); // closing timer / 100 to update on every percent + m_statefulGaragePercentageTimer.insert(thing, timer); + connect(thing, &Thing::settingChanged, thing, [timer] (const ParamTypeId ¶mTypeId, const QVariant &value) { + if (paramTypeId == extendedStatefulGaragedoorSettingsOpeningDurationParamTypeId) { + timer->setInterval(value.toUInt()/100.00); + } + }); + connect(timer, &QTimer::timeout, this, [thing, timer, this] { + uint currentPercentage = thing->stateValue(extendedStatefulGaragedoorPercentageStateTypeId).toUInt(); + uint targetPercentage = m_statefulGarageTargetPercentage.value(thing); + + if (currentPercentage < targetPercentage) { + currentPercentage++; + thing->setStateValue(extendedStatefulGaragedoorPercentageStateTypeId, currentPercentage); + thing->setStateValue(extendedStatefulGaragedoorStateStateTypeId, "closing"); + thing->setStateValue(extendedStatefulGaragedoorMovingStateTypeId, true); + thing->setStateValue(extendedStatefulGaragedoorOpeningOutputStateTypeId, false); + thing->setStateValue(extendedStatefulGaragedoorClosingOutputStateTypeId, true); + + } else if (currentPercentage > targetPercentage) { + currentPercentage--; + thing->setStateValue(extendedStatefulGaragedoorPercentageStateTypeId, currentPercentage); + thing->setStateValue(extendedStatefulGaragedoorStateStateTypeId, "opening"); + thing->setStateValue(extendedStatefulGaragedoorMovingStateTypeId, true); + thing->setStateValue(extendedStatefulGaragedoorOpeningOutputStateTypeId, true); + thing->setStateValue(extendedStatefulGaragedoorClosingOutputStateTypeId, false); + + } + + if (currentPercentage == targetPercentage){ + QString state = currentPercentage == 100 ? "open" : currentPercentage == 0 ? "closed" : "intermediate"; + thing->setStateValue(extendedStatefulGaragedoorStateStateTypeId, state); + thing->setStateValue(extendedStatefulGaragedoorMovingStateTypeId, false); + thing->setStateValue(extendedStatefulGaragedoorOpeningOutputStateTypeId, false); + thing->setStateValue(extendedStatefulGaragedoorClosingOutputStateTypeId, false); + qCDebug(dcGenericThings()) << "Stopping garage timer"; + timer->stop(); + } + }); } info->finish(Thing::ThingErrorNoError); } @@ -536,6 +575,57 @@ void IntegrationPluginGenericThings::executeAction(ThingActionInfo *info) } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } + } else if (thing->thingClassId() == impulseGaragedooorThingClassId) { + if (action.actionTypeId() == impulseGaragedooorTriggerImpulseActionTypeId) { + uint duration = thing->setting(impulseGaragedooorSettingsImpulseDurationParamTypeId).toUInt(); + thing->setStateValue(impulseGaragedooorImpulseStateTypeId, true); + QTimer::singleShot(duration, thing, [thing](){ + thing->setStateValue(impulseGaragedooorImpulseStateTypeId, false); + }); + info->finish(Thing::ThingErrorNoError); + return; + } + Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); + } else if (thing->thingClassId() == simpleGaragedoorThingClassId) { + if (action.actionTypeId() == simpleGaragedoorOpenActionTypeId) { + thing->setStateValue(simpleGaragedoorClosingOutputStateTypeId, false); + thing->setStateValue(simpleGaragedoorOpeningOutputStateTypeId, true); + info->finish(Thing::ThingErrorNoError); + return; + } + if (action.actionTypeId() == simpleGaragedoorCloseActionTypeId) { + thing->setStateValue(simpleGaragedoorOpeningOutputStateTypeId, false); + thing->setStateValue(simpleGaragedoorClosingOutputStateTypeId, true); + info->finish(Thing::ThingErrorNoError); + return; + } + if (action.actionTypeId() == simpleGaragedoorStopActionTypeId) { + thing->setStateValue(simpleGaragedoorClosingOutputStateTypeId, false); + thing->setStateValue(simpleGaragedoorOpeningOutputStateTypeId, false); + info->finish(Thing::ThingErrorNoError); + return; + } + Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); + } else if (thing->thingClassId() == extendedStatefulGaragedoorThingClassId) { + if (action.actionTypeId() == extendedStatefulGaragedoorOpenActionTypeId) { + m_statefulGarageTargetPercentage[thing] = 0; + m_statefulGaragePercentageTimer[thing]->start(); + info->finish(Thing::ThingErrorNoError); + return; + } + if (action.actionTypeId() == extendedStatefulGaragedoorCloseActionTypeId) { + m_statefulGarageTargetPercentage[thing] = 100; + m_statefulGaragePercentageTimer[thing]->start(); + info->finish(Thing::ThingErrorNoError); + return; + } + if (action.actionTypeId() == extendedStatefulGaragedoorStopActionTypeId) { + m_statefulGarageTargetPercentage[thing] = thing->stateValue(extendedStatefulGaragedoorPercentageStateTypeId).toUInt(); + info->finish(Thing::ThingErrorNoError); + return; + } + + 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()); } diff --git a/genericthings/integrationplugingenericthings.h b/genericthings/integrationplugingenericthings.h index bba4e8f..e831b8b 100644 --- a/genericthings/integrationplugingenericthings.h +++ b/genericthings/integrationplugingenericthings.h @@ -59,6 +59,8 @@ private: QHash m_smartMeterTimer; QHash m_extendedBlindTargetPercentage; QHash m_venetianBlindTargetAngle; + QHash m_statefulGaragePercentageTimer; + QHash m_statefulGarageTargetPercentage; enum BlindState { BlindStateOpening, diff --git a/genericthings/integrationplugingenericthings.json b/genericthings/integrationplugingenericthings.json index ad08d92..700a3ae 100644 --- a/genericthings/integrationplugingenericthings.json +++ b/genericthings/integrationplugingenericthings.json @@ -133,16 +133,16 @@ { "id": "40aa9f3c-a23c-4f7f-8786-fcf3554f3e19", "name": "extendedBlind", - "displayName": "Generic extended blind", + "displayName": "Generic blind with position control", "createMethods": ["user"], "interfaces": ["extendedblind"], "settingsTypes": [ { "id": "27a95b8d-7f97-441b-a3be-0646c517cb06", - "name": "closingTime", - "displayName": "Closing time [MilliSecond]", + "name": "closingDuration", + "displayName": "Closing duration [ms]", "type": "uint", - "minValue": 1, + "minValue": 1000, "defaultValue": 5000 } ], @@ -231,16 +231,16 @@ "settingsTypes": [ { "id": "4c0bf07d-aaab-4f67-af65-00ceaefbaa84", - "name": "closingTime", - "displayName": "Closing time [MilliSecond]", - "minValue": 1, + "name": "closingDuration", + "displayName": "Closing duration [ms]", + "minValue": 1000, "type": "uint", "defaultValue": 5000 }, { "id": "6c8340bf-7fd3-43e3-a75b-dfa2f6426e11", "name": "angleTime", - "displayName": "Angle end to end time [MilliSecond]", + "displayName": "Angle end to end time [ms]", "minValue": 1, "type": "uint", "defaultValue": 1000 @@ -396,6 +396,167 @@ } ] }, + { + "id": "d6699a12-f4a6-4c50-951c-f4f1cd0501dc", + "name": "impulseGaragedooor", + "displayName": "Impulse based garage door", + "createMethods": ["user"], + "interfaces": ["impulsegaragedoor"], + "settingsTypes": [ + { + "id": "962b356c-e975-4d33-b114-10f655eaf74c", + "name": "impulseDuration", + "displayName": "Impulse duration", + "type": "uint", + "defaultValue": "200" + } + ], + "actionTypes": [ + { + "id": "ff5461c6-70fc-435e-8424-96fa59ed321e", + "name": "triggerImpulse", + "displayName": "Operate" + } + ], + "stateTypes": [ + { + "id": "5ccaf0aa-01a4-441f-b6ca-18940da096a5", + "name": "impulse", + "displayName": "Impulse", + "displayNameEvent": "Impulse changed", + "type": "bool", + "defaultValue": false, + "ioType": "digitalInput" + } + ] + }, + { + "id": "572403b1-bc22-4620-8170-53147a546033", + "name": "simpleGaragedoor", + "displayName": "Simple garage door", + "createMethods": ["user"], + "interfaces": ["simplegaragedoor"], + "actionTypes": [ + { + "id": "3edb25af-ad51-495b-9ac9-ab97669339b7", + "name": "open", + "displayName": "Open" + }, + { + "id": "1111c0ed-69b6-480c-9fd5-15292600d4f4", + "name": "close", + "displayName": "Close" + }, + { + "id": "f346766f-44ee-452b-bb9c-e89ec0f56016", + "name": "stop", + "displayName": "Stop" + } + ], + "stateTypes": [ + { + "id": "fcd421eb-54f2-4195-bdef-ffa69e9dcc57", + "name": "openingOutput", + "displayName": "Opening output", + "displayNameEvent": "Opening output changed", + "type": "bool", + "defaultValue": false, + "ioType": "digitalInput" + }, + { + "id": "44ef060a-e6fc-4f33-84d2-b24ac7d31ff1", + "name": "closingOutput", + "displayName": "Closing output", + "displayNameEvent": "Closing output changed", + "type": "bool", + "defaultValue": false, + "ioType": "digitalInput" + } + ] + }, + { + "id": "7341e689-4495-4422-851a-3e7c790394b8", + "name": "extendedStatefulGaragedoor", + "displayName": "Garage door with position control", + "createMethods": ["user"], + "interfaces": ["extendedstatefulgaragedoor"], + "settingsTypes": [ + { + "id": "04fb7724-a870-4df9-a79e-fab693931238", + "name": "openingDuration", + "displayName": "Opening duration [ms]", + "type": "uint", + "minValue": 1000, + "defaultValue": 5000 + } + ], + "stateTypes": [ + { + "id": "0cc74edb-7116-47cf-953a-409933f26557", + "name": "state", + "displayName": "State", + "displayNameEvent": "State changed", + "type": "QString", + "possibleValues": ["open", "closed", "opening", "closing", "intermediate"], + "defaultValue": "closed" + }, + { + "id": "963bed3d-2ccb-4dd0-b609-c7e9f25d32d6", + "name": "moving", + "displayName": "Moving", + "displayNameEvent": "Moving changed", + "type": "bool", + "defaultValue": false + }, + { + "id": "f9244c14-0bc9-49ce-90a5-437e66245594", + "name": "percentage", + "displayName": "Open position", + "displayNameEvent": "Open position changed", + "displayNameAction": "Set open position", + "type": "int", + "minValue": 0, + "maxValue": 100, + "defaultValue": 100, + "writable": true + }, + { + "id": "ecc799c7-4d74-4d1f-94e5-2d74e77493ae", + "name": "openingOutput", + "displayName": "Opening output", + "displayNameEvent": "Opening output changed", + "type": "bool", + "defaultValue": false, + "ioType": "digitalInput" + }, + { + "id": "e1c14bcd-6131-494b-8dd1-46738e9c8f5e", + "name": "closingOutput", + "displayName": "Closing output", + "displayNameEvent": "Closing output changed", + "type": "bool", + "defaultValue": false, + "ioType": "digitalInput" + } + ], + "actionTypes": [ + { + "id": "4a3a3b88-47e9-436f-86be-b5955f3fc2f7", + "name": "open", + "displayName": "Open" + }, + { + "id": "2420fcdb-03d3-4edb-aa89-e3b93c7d6d18", + "name": "close", + "displayName": "Close" + }, + { + "id": "109c3eaf-26a0-4121-8be2-1363253178fd", + "name": "stop", + "displayName": "Stop" + } + ] + }, { "id": "4e7261af-a27b-4446-8346-914ea59f7547", "name": "socket",