From 322bcf56a600f56e6320b212102b89c3aa7f493a Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 9 May 2020 15:14:11 +0200 Subject: [PATCH] Add support for inverting the connections --- .../thingmanagerimplementation.cpp | 44 ++++++++---- .../integrations/thingmanagerimplementation.h | 3 +- libnymea-core/jsonrpc/actionhandler.cpp | 2 +- libnymea-core/jsonrpc/integrationshandler.cpp | 4 +- libnymea/integrations/ioconnection.cpp | 10 ++- libnymea/integrations/ioconnection.h | 6 +- libnymea/integrations/thingmanager.cpp | 4 +- libnymea/integrations/thingmanager.h | 2 +- plugins/mock/integrationpluginmock.cpp | 4 +- plugins/mock/integrationpluginmock.json | 2 +- tests/auto/api.json | 2 + .../auto/ioconnections/testioconnections.cpp | 70 ++++++++++++++----- 12 files changed, 112 insertions(+), 41 deletions(-) diff --git a/libnymea-core/integrations/thingmanagerimplementation.cpp b/libnymea-core/integrations/thingmanagerimplementation.cpp index 3516c998..568c8cd9 100644 --- a/libnymea-core/integrations/thingmanagerimplementation.cpp +++ b/libnymea-core/integrations/thingmanagerimplementation.cpp @@ -1005,6 +1005,11 @@ IOConnectionResult ThingManagerImplementation::connectIO(const IOConnection &con emit ioConnectionAdded(connection); + qCDebug(dcThingManager()) << "IO connected added:" << inputThing << "->" << outputThing; + + // Sync initial state + syncIOConnection(inputThing, connection.inputStateTypeId()); + result.error = Thing::ThingErrorNoError; result.ioConnectionId = connection.id(); return result; @@ -1736,9 +1741,18 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s Event event(EventTypeId(stateTypeId.toString()), thing->id(), ParamList() << valueParam, true); emit eventTriggered(event); + syncIOConnection(thing, stateTypeId); +} + +void ThingManagerImplementation::syncIOConnection(Thing *thing, const StateTypeId &stateTypeId) +{ + foreach (const IOConnection &ioConnection, m_ioConnections) { // Check if this state is an input to an IO connection. if (ioConnection.inputThingId() == thing->id() && ioConnection.inputStateTypeId() == stateTypeId) { + Thing *inputThing = thing; + QVariant inputValue = inputThing->stateValue(stateTypeId); + Thing *outputThing = m_configuredThings.value(ioConnection.outputThingId()); if (!outputThing) { qCWarning(dcThingManager()) << "IO connection contains invalid output thing!"; @@ -1749,7 +1763,7 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s qCWarning(dcThingManager()) << "Plugin not found for IO connection's output action."; continue; } - StateType inputStateType = thing->thingClass().getStateType(stateTypeId); + StateType inputStateType = inputThing->thingClass().getStateType(stateTypeId); StateType outputStateType = outputThing->thingClass().getStateType(ioConnection.outputStateTypeId()); if (outputStateType.id().isNull()) { @@ -1759,7 +1773,7 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s QVariant outputValue; if (outputStateType.ioType() == Types::IOTypeDigitalOutput) { // Digital IOs are mapped as-is - outputValue = value; + outputValue = ioConnection.inverted() xor inputValue.toBool(); // We're already in sync! Skipping action. if (outputThing->stateValue(outputStateType.id()) == outputValue) { @@ -1767,10 +1781,10 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s } } else { // Analog IOs are mapped within the according min/max ranges - outputValue = mapValue(value, inputStateType, outputStateType); + outputValue = mapValue(inputValue, inputStateType, outputStateType, ioConnection.inverted()); // We're already in sync (fuzzy, good enough)! Skipping action. - if (qFuzzyCompare(outputThing->stateValue(outputStateType.id()).toDouble(), outputValue.toDouble())) { + if (qFuzzyCompare(1.0 + outputThing->stateValue(outputStateType.id()).toDouble(), 1.0 + outputValue.toDouble())) { continue; } } @@ -1785,9 +1799,9 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s // An error happened... let's switch the input back to be in sync with the output qCWarning(dcThingManager()) << "Error syncing IO connection state. Reverting input back to old value."; if (inputStateType.ioType() == Types::IOTypeDigitalInput) { - thing->setStateValue(inputStateType.id(), outputThing->stateValue(outputStateType.id())); + inputThing->setStateValue(inputStateType.id(), outputThing->stateValue(outputStateType.id())); } else { - thing->setStateValue(inputStateType.id(), mapValue(outputThing->stateValue(outputStateType.id()), outputStateType, inputStateType)); + inputThing->setStateValue(inputStateType.id(), mapValue(outputThing->stateValue(outputStateType.id()), outputStateType, inputStateType, ioConnection.inverted())); } } }); @@ -1795,6 +1809,9 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s // Now check if this is an output state type and - if possible - update the inputs for bidirectional connections if (ioConnection.outputThingId() == thing->id() && ioConnection.outputStateTypeId() == stateTypeId) { + Thing *outputThing = thing; + QVariant outputValue = outputThing->stateValue(stateTypeId); + Thing *inputThing = m_configuredThings.value(ioConnection.inputThingId()); if (!inputThing) { qCWarning(dcThingManager()) << "IO connection contains invalid input thing!"; @@ -1805,7 +1822,7 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s qCWarning(dcThingManager()) << "Plugin not found for IO connection's input action."; continue; } - StateType outputStateType = thing->thingClass().getStateType(stateTypeId); + StateType outputStateType = outputThing->thingClass().getStateType(stateTypeId); StateType inputStateType = inputThing->thingClass().getStateType(ioConnection.inputStateTypeId()); if (inputStateType.id().isNull()) { @@ -1821,7 +1838,7 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s QVariant inputValue; if (inputStateType.ioType() == Types::IOTypeDigitalInput) { // Digital IOs are mapped as-is - inputValue = value; + inputValue = ioConnection.inverted() xor outputValue.toBool(); // Prevent looping if (inputThing->stateValue(inputStateType.id()) == inputValue) { @@ -1829,10 +1846,10 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s } } else { // Analog IOs are mapped within the according min/max ranges - inputValue = mapValue(value, outputStateType, inputStateType); + inputValue = mapValue(outputValue, outputStateType, inputStateType, ioConnection.inverted()); // Prevent looping even if the above calculation has rounding errors... Just skip this action if we're close enough already - if (qFuzzyCompare(inputThing->stateValue(inputStateType.id()).toDouble(), inputValue.toDouble())) { + if (qFuzzyCompare(1.0 + inputThing->stateValue(inputStateType.id()).toDouble(), 1.0 + inputValue.toDouble())) { continue; } } @@ -2000,6 +2017,7 @@ void ThingManagerImplementation::storeIOConnections() connectionSettings.setValue("inputStateTypeId", ioConnection.inputStateTypeId().toString()); connectionSettings.setValue("outputThingId", ioConnection.outputThingId().toString()); connectionSettings.setValue("outputStateTypeId", ioConnection.outputStateTypeId().toString()); + connectionSettings.setValue("inverted", ioConnection.inverted()); connectionSettings.endGroup(); } @@ -2017,14 +2035,15 @@ void ThingManagerImplementation::loadIOConnections() StateTypeId inputStateTypeId = connectionSettings.value("inputStateTypeId").toUuid(); ThingId outputThingId = connectionSettings.value("outputThingId").toUuid(); StateTypeId outputStateTypeId = connectionSettings.value("outputStateTypeId").toUuid(); - IOConnection ioConnection(id, inputThingId, inputStateTypeId, outputThingId, outputStateTypeId); + bool inverted = connectionSettings.value("inverted").toBool(); + IOConnection ioConnection(id, inputThingId, inputStateTypeId, outputThingId, outputStateTypeId, inverted); m_ioConnections.insert(id, ioConnection); connectionSettings.endGroup(); } connectionSettings.endGroup(); } -QVariant ThingManagerImplementation::mapValue(const QVariant &value, const StateType &fromStateType, const StateType &toStateType) const +QVariant ThingManagerImplementation::mapValue(const QVariant &value, const StateType &fromStateType, const StateType &toStateType, bool inverted) const { double fromMin = fromStateType.minValue().toDouble(); double fromMax = fromStateType.maxValue().toDouble(); @@ -2032,6 +2051,7 @@ QVariant ThingManagerImplementation::mapValue(const QVariant &value, const State double toMax = toStateType.maxValue().toDouble(); double fromValue = value.toDouble(); double fromPercent = (fromValue - fromMin) / (fromMax - fromMin); + fromPercent = inverted ? 1 - fromPercent : fromPercent; double toValue = toMin + (toMax - toMin) * fromPercent; return toValue; } diff --git a/libnymea-core/integrations/thingmanagerimplementation.h b/libnymea-core/integrations/thingmanagerimplementation.h index 8f579f8b..51f51e4d 100644 --- a/libnymea-core/integrations/thingmanagerimplementation.h +++ b/libnymea-core/integrations/thingmanagerimplementation.h @@ -157,7 +157,8 @@ private: void storeIOConnections(); void loadIOConnections(); - QVariant mapValue(const QVariant &value, const StateType &fromStateType, const StateType &toStateType) const; + void syncIOConnection(Thing *inputThing, const StateTypeId &stateTypeId); + QVariant mapValue(const QVariant &value, const StateType &fromStateType, const StateType &toStateType, bool inverted) const; private: HardwareManager *m_hardwareManager; diff --git a/libnymea-core/jsonrpc/actionhandler.cpp b/libnymea-core/jsonrpc/actionhandler.cpp index 21915436..4a6721fe 100644 --- a/libnymea-core/jsonrpc/actionhandler.cpp +++ b/libnymea-core/jsonrpc/actionhandler.cpp @@ -176,7 +176,7 @@ JsonReply *ActionHandler::ExecuteBrowserItemAction(const QVariantMap ¶ms) BrowserItemActionInfo *info = NymeaCore::instance()->executeBrowserItemAction(browserItemAction); connect(info, &BrowserItemActionInfo::finished, jsonReply, [info, jsonReply](){ QVariantMap data; - data.insert("deviceError", enumValueName(info->status()).replace("ThingError", "DeviceError")); + data.insert("deviceError", enumValueName(info->status()).replace("Thing", "Device")); jsonReply->setData(data); jsonReply->finished(); }); diff --git a/libnymea-core/jsonrpc/integrationshandler.cpp b/libnymea-core/jsonrpc/integrationshandler.cpp index bab65155..158c4f8c 100644 --- a/libnymea-core/jsonrpc/integrationshandler.cpp +++ b/libnymea-core/jsonrpc/integrationshandler.cpp @@ -361,6 +361,7 @@ IntegrationsHandler::IntegrationsHandler(ThingManager *thingManager, QObject *pa params.insert("inputStateTypeId", enumValueName(Uuid)); params.insert("outputThingId", enumValueName(Uuid)); params.insert("outputStateTypeId", enumValueName(Uuid)); + params.insert("o:inverted", enumValueName(Bool)); returns.insert("thingError", enumRef()); returns.insert("o:ioConnectionId", enumValueName(Uuid)); registerMethod("ConnectIO", description, params, returns); @@ -992,7 +993,8 @@ JsonReply *IntegrationsHandler::ConnectIO(const QVariantMap ¶ms) StateTypeId inputStateTypeId = params.value("inputStateTypeId").toUuid(); ThingId outputThingId = params.value("outputThingId").toUuid(); StateTypeId outputStateTypeId = params.value("outputStateTypeId").toUuid(); - IOConnectionResult result = m_thingManager->connectIO(inputThingId, inputStateTypeId, outputThingId, outputStateTypeId); + bool inverted = params.value("inverted", false).toBool(); + IOConnectionResult result = m_thingManager->connectIO(inputThingId, inputStateTypeId, outputThingId, outputStateTypeId, inverted); QVariantMap reply = statusToReply(result.error); if (result.error == Thing::ThingErrorNoError) { reply.insert("ioConnectionId", result.ioConnectionId); diff --git a/libnymea/integrations/ioconnection.cpp b/libnymea/integrations/ioconnection.cpp index e408df54..b56aa53b 100644 --- a/libnymea/integrations/ioconnection.cpp +++ b/libnymea/integrations/ioconnection.cpp @@ -5,12 +5,13 @@ IOConnection::IOConnection() } -IOConnection::IOConnection(const IOConnectionId &id, const ThingId &inputThing, const StateTypeId &inputState, const ThingId &outputThing, const StateTypeId &outputState): +IOConnection::IOConnection(const IOConnectionId &id, const ThingId &inputThing, const StateTypeId &inputState, const ThingId &outputThing, const StateTypeId &outputState, bool inverted): m_id(id), m_inputThingId(inputThing), m_inputStateTypeId(inputState), m_outputThingId(outputThing), - m_outputStateTypeId(outputState) + m_outputStateTypeId(outputState), + m_inverted(inverted) { } @@ -40,6 +41,11 @@ StateTypeId IOConnection::outputStateTypeId() const return m_outputStateTypeId; } +bool IOConnection::inverted() const +{ + return m_inverted; +} + QVariant IOConnections::get(int index) const { return QVariant::fromValue(at(index)); diff --git a/libnymea/integrations/ioconnection.h b/libnymea/integrations/ioconnection.h index 207cbd71..7cb124de 100644 --- a/libnymea/integrations/ioconnection.h +++ b/libnymea/integrations/ioconnection.h @@ -21,10 +21,11 @@ class IOConnection Q_PROPERTY(QUuid inputStateTypeId READ inputStateTypeId) Q_PROPERTY(QUuid outputThingId READ outputThingId) Q_PROPERTY(QUuid outputStateTypeId READ outputStateTypeId) + Q_PROPERTY(bool inverted READ inverted) public: IOConnection(); - IOConnection(const IOConnectionId &id, const ThingId &inputThingId, const StateTypeId &inputStateTypeId, const ThingId &outputThingId, const StateTypeId &outputStateTypeId); + IOConnection(const IOConnectionId &id, const ThingId &inputThingId, const StateTypeId &inputStateTypeId, const ThingId &outputThingId, const StateTypeId &outputStateTypeId, bool inverted = false); IOConnectionId id() const; @@ -34,12 +35,15 @@ public: ThingId outputThingId() const; StateTypeId outputStateTypeId() const; + bool inverted() const; + private: IOConnectionId m_id; ThingId m_inputThingId; StateTypeId m_inputStateTypeId; ThingId m_outputThingId; StateTypeId m_outputStateTypeId; + bool m_inverted = false; }; class IOConnections: public QList diff --git a/libnymea/integrations/thingmanager.cpp b/libnymea/integrations/thingmanager.cpp index 53d41a47..c427cda3 100644 --- a/libnymea/integrations/thingmanager.cpp +++ b/libnymea/integrations/thingmanager.cpp @@ -51,8 +51,8 @@ ThingManager::ThingManager(QObject *parent) : QObject(parent) qRegisterMetaType(); } -IOConnectionResult ThingManager::connectIO(const ThingId &inputThing, const StateTypeId &inputState, const ThingId &outputThing, const StateTypeId &outputState) +IOConnectionResult ThingManager::connectIO(const ThingId &inputThing, const StateTypeId &inputState, const ThingId &outputThing, const StateTypeId &outputState, bool inverted) { - IOConnection connection(IOConnectionId::createIOConnectionId(), inputThing, inputState, outputThing, outputState); + IOConnection connection(IOConnectionId::createIOConnectionId(), inputThing, inputState, outputThing, outputState, inverted); return connectIO(connection); } diff --git a/libnymea/integrations/thingmanager.h b/libnymea/integrations/thingmanager.h index 0b234591..c846845e 100644 --- a/libnymea/integrations/thingmanager.h +++ b/libnymea/integrations/thingmanager.h @@ -91,7 +91,7 @@ public: virtual BrowserItemActionInfo* executeBrowserItemAction(const BrowserItemAction &browserItemAction) = 0; virtual IOConnections ioConnections(const ThingId &thingId = ThingId()) const = 0; - IOConnectionResult connectIO(const ThingId &inputThing, const StateTypeId &inputState, const ThingId &outputThing, const StateTypeId &outputState); + IOConnectionResult connectIO(const ThingId &inputThing, const StateTypeId &inputState, const ThingId &outputThing, const StateTypeId &outputState, bool inverted = false); virtual Thing::ThingError disconnectIO(const IOConnectionId &ioConnectionId) = 0; virtual QString translate(const PluginId &pluginId, const QString &string, const QLocale &locale) = 0; diff --git a/plugins/mock/integrationpluginmock.cpp b/plugins/mock/integrationpluginmock.cpp index 409cb268..42c5cc6b 100644 --- a/plugins/mock/integrationpluginmock.cpp +++ b/plugins/mock/integrationpluginmock.cpp @@ -749,11 +749,11 @@ void IntegrationPluginMock::executeAction(ThingActionInfo *info) if (info->thing()->thingClassId() == virtualIoTemperatureSensorMockThingClassId) { if (info->action().actionTypeId() == virtualIoTemperatureSensorMockInputActionTypeId) { + double value = info->action().param(virtualIoTemperatureSensorMockInputActionInputParamTypeId).value().toDouble(); + info->thing()->setStateValue(virtualIoTemperatureSensorMockInputStateTypeId, value); double minTemp = info->thing()->setting(virtualIoTemperatureSensorMockSettingsMinTempParamTypeId).toDouble(); double maxTemp = info->thing()->setting(virtualIoTemperatureSensorMockSettingsMaxTempParamTypeId).toDouble(); - double value = info->action().param(virtualIoTemperatureSensorMockInputActionInputParamTypeId).value().toDouble(); double temp = minTemp + (maxTemp - minTemp) * value; - qCDebug(dcMock()) << "Min:" << minTemp << "Max:" << maxTemp << "value:" << value << "temp:" << temp; info->thing()->setStateValue(virtualIoTemperatureSensorMockTemperatureStateTypeId, temp); info->finish(Thing::ThingErrorNoError); return; diff --git a/plugins/mock/integrationpluginmock.json b/plugins/mock/integrationpluginmock.json index cd67c5e0..eb4713d3 100644 --- a/plugins/mock/integrationpluginmock.json +++ b/plugins/mock/integrationpluginmock.json @@ -1035,7 +1035,7 @@ "displayNameEvent": "Temperature changed", "type": "double", "unit": "DegreeCelsius", - "defaultValue": 0 + "defaultValue": -20 } ] } diff --git a/tests/auto/api.json b/tests/auto/api.json index 3785c079..3b5ffff8 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -949,6 +949,7 @@ "params": { "inputStateTypeId": "Uuid", "inputThingId": "Uuid", + "o:inverted": "Bool", "outputStateTypeId": "Uuid", "outputThingId": "Uuid" }, @@ -2456,6 +2457,7 @@ "r:id": "Uuid", "r:inputStateTypeId": "Uuid", "r:inputThingId": "Uuid", + "r:inverted": "Bool", "r:outputStateTypeId": "Uuid", "r:outputThingId": "Uuid" }, diff --git a/tests/auto/ioconnections/testioconnections.cpp b/tests/auto/ioconnections/testioconnections.cpp index 1bda1c73..13f1c5c7 100644 --- a/tests/auto/ioconnections/testioconnections.cpp +++ b/tests/auto/ioconnections/testioconnections.cpp @@ -60,8 +60,10 @@ private slots: void testConnectionCompatibility_data(); void testConnectionCompatibility(); + void testDigitalIO_data(); void testDigitalIO(); + void testAnalogIO_data(); void testAnalogIO(); }; @@ -71,6 +73,7 @@ void TestIOConnections::initTestCase() QLoggingCategory::setFilterRules("*.debug=false\n" "Tests.debug=true\n" "Mock.debug=true\n" + "ThingManager.debug=true\n" ); // Adding generic IO mock @@ -151,33 +154,47 @@ void TestIOConnections::testConnectionCompatibility() } +void TestIOConnections::testDigitalIO_data() +{ + QTest::addColumn("inverted"); + + QTest::newRow("normal") << false; + QTest::newRow("inverted") << true; +} + void TestIOConnections::testDigitalIO() { + QFETCH(bool, inverted); + QVariantMap params; params.insert("inputThingId", m_lightThingId); params.insert("inputStateTypeId", virtualIoLightMockPowerStateTypeId); params.insert("outputThingId", m_ioThingId); params.insert("outputStateTypeId", genericIoMockDigitalOutput1StateTypeId); + params.insert("inverted", inverted); QVariant response = injectAndWait("Integrations.ConnectIO", params); verifyThingError(response); IOConnectionId ioConnectionId = response.toMap().value("params").toMap().value("ioConnectionId").toUuid(); - // verify both, input and out are off + // verify input is off + bool expectedValue = false; params.clear(); params.insert("thingId", m_lightThingId); params.insert("stateTypeId", virtualIoLightMockPowerStateTypeId); response = injectAndWait("Integrations.GetStateValue", params); verifyThingError(response); - QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == false, "Light isn't turned off"); + QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == expectedValue, "Light isn't turned off"); + // verify output is off (or inverted) params.clear(); params.insert("thingId", m_ioThingId); params.insert("stateTypeId", genericIoMockDigitalOutput1StateTypeId); response = injectAndWait("Integrations.GetStateValue", params); verifyThingError(response); - QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == false, "Digital output isn't turned off"); + QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == (expectedValue xor inverted), "Digital output isn't turned off"); // Turn on light and verify digital output went on + expectedValue = true; params.clear(); params.insert("thingId", m_lightThingId); params.insert("actionTypeId", virtualIoLightMockPowerActionTypeId); @@ -193,7 +210,7 @@ void TestIOConnections::testDigitalIO() params.insert("stateTypeId", genericIoMockDigitalOutput1StateTypeId); response = injectAndWait("Integrations.GetStateValue", params); verifyThingError(response); - QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == true, "Digital output isn't turned on"); + QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == (expectedValue xor inverted), "Digital output isn't turned on"); // Disconnect IO again params.clear(); @@ -202,6 +219,7 @@ void TestIOConnections::testDigitalIO() verifyThingError(response); // Turn off the light and verify digital output is still on + expectedValue = true; params.clear(); params.insert("thingId", m_lightThingId); params.insert("actionTypeId", virtualIoLightMockPowerActionTypeId); @@ -217,41 +235,59 @@ void TestIOConnections::testDigitalIO() params.insert("stateTypeId", genericIoMockDigitalOutput1StateTypeId); response = injectAndWait("Integrations.GetStateValue", params); verifyThingError(response); - QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == true, "Digital output turned off while it should not"); + QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == (expectedValue xor inverted), "Digital output turned off while it should not"); +} + +void TestIOConnections::testAnalogIO_data() +{ + QTest::addColumn("inverted"); + + QTest::newRow("normal") << false; + QTest::newRow("inverted") << true; } void TestIOConnections::testAnalogIO() { + QFETCH(bool, inverted); + + // Set input to 0 QVariantMap params; + params.insert("thingId", m_ioThingId); + params.insert("actionTypeId", genericIoMockAnalogInput1StateTypeId); + QVariantMap actionParam; + actionParam.insert("paramTypeId", genericIoMockAnalogInput1ActionAnalogInput1ParamTypeId); + actionParam.insert("value", 0); // goes from 0 to 3.3 + params.insert("params", QVariantList() << actionParam); + QVariant response = injectAndWait("Integrations.ExecuteAction", params); + verifyThingError(response); + + // Connect IO to it + params.clear(); params.insert("inputThingId", m_ioThingId); params.insert("inputStateTypeId", genericIoMockAnalogInput1StateTypeId); params.insert("outputThingId", m_tempSensorThingId); params.insert("outputStateTypeId", virtualIoTemperatureSensorMockInputStateTypeId); - QVariant response = injectAndWait("Integrations.ConnectIO", params); + params.insert("inverted", inverted); + + response = injectAndWait("Integrations.ConnectIO", params); verifyThingError(response); IOConnectionId ioConnectionId = response.toMap().value("params").toMap().value("ioConnectionId").toUuid(); - // verify input is at 0, temp at 0 too - params.clear(); - params.insert("thingId", m_ioThingId); - params.insert("stateTypeId", genericIoMockAnalogInput1StateTypeId); - response = injectAndWait("Integrations.GetStateValue", params); - verifyThingError(response); - QVERIFY2(qFuzzyCompare(response.toMap().value("params").toMap().value("value").toDouble(), 0), "Input isn't at 0"); - + // and check temp senser + double expectedTemp = inverted ? 50 : -20; params.clear(); params.insert("thingId", m_tempSensorThingId); params.insert("stateTypeId", virtualIoTemperatureSensorMockTemperatureStateTypeId); response = injectAndWait("Integrations.GetStateValue", params); verifyThingError(response); - QVERIFY2(qFuzzyCompare(response.toMap().value("params").toMap().value("value").toDouble(), 0), QString("Temp sensor is not at 0 but at %1").arg(response.toMap().value("params").toMap().value("value").toDouble()).toUtf8()); + QVERIFY2(qFuzzyCompare(response.toMap().value("params").toMap().value("value").toDouble(), expectedTemp), QString("Temp sensor is not at %1 but at %2").arg(expectedTemp).arg(response.toMap().value("params").toMap().value("value").toDouble()).toUtf8()); // set analog input to 0.5 and verify temp aligned params.clear(); params.insert("thingId", m_ioThingId); params.insert("actionTypeId", genericIoMockAnalogInput1StateTypeId); - QVariantMap actionParam; + actionParam.clear(); actionParam.insert("paramTypeId", genericIoMockAnalogInput1ActionAnalogInput1ParamTypeId); actionParam.insert("value", 1.65); // goes from 0 to 3.3 params.insert("params", QVariantList() << actionParam); @@ -265,7 +301,7 @@ void TestIOConnections::testAnalogIO() verifyThingError(response); // generic IO output goes from 0 to 3.3. We're setting 1.65V which 50% // temp goes from -20 to 50. A input of 1.65 should output a temperature of 15°C - double expectedTemp = 70.0 / 2 - 20; + expectedTemp = 70.0 / 2 - 20; QVERIFY2(qFuzzyCompare(response.toMap().value("params").toMap().value("value").toDouble(), expectedTemp), QString("Temp sensor is not at %1 but at %2").arg(expectedTemp).arg(response.toMap().value("params").toMap().value("value").toDouble()).toUtf8()); // Disconnect IO again