mirror of https://github.com/nymea/nymea.git
Add support for inverting the connections
parent
4e509d75f8
commit
322bcf56a6
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<Thing::ThingError>(info->status()).replace("ThingError", "DeviceError"));
|
||||
data.insert("deviceError", enumValueName<Thing::ThingError>(info->status()).replace("Thing", "Device"));
|
||||
jsonReply->setData(data);
|
||||
jsonReply->finished();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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<Thing::ThingError>());
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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<IOConnection>
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ ThingManager::ThingManager(QObject *parent) : QObject(parent)
|
|||
qRegisterMetaType<ParamTypes>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1035,7 +1035,7 @@
|
|||
"displayNameEvent": "Temperature changed",
|
||||
"type": "double",
|
||||
"unit": "DegreeCelsius",
|
||||
"defaultValue": 0
|
||||
"defaultValue": -20
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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<bool>("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<bool>("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
|
||||
|
|
|
|||
Loading…
Reference in New Issue