Add support for inverting the connections
This commit is contained in:
parent
4e509d75f8
commit
322bcf56a6
@ -1005,6 +1005,11 @@ IOConnectionResult ThingManagerImplementation::connectIO(const IOConnection &con
|
|||||||
|
|
||||||
emit ioConnectionAdded(connection);
|
emit ioConnectionAdded(connection);
|
||||||
|
|
||||||
|
qCDebug(dcThingManager()) << "IO connected added:" << inputThing << "->" << outputThing;
|
||||||
|
|
||||||
|
// Sync initial state
|
||||||
|
syncIOConnection(inputThing, connection.inputStateTypeId());
|
||||||
|
|
||||||
result.error = Thing::ThingErrorNoError;
|
result.error = Thing::ThingErrorNoError;
|
||||||
result.ioConnectionId = connection.id();
|
result.ioConnectionId = connection.id();
|
||||||
return result;
|
return result;
|
||||||
@ -1736,9 +1741,18 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s
|
|||||||
Event event(EventTypeId(stateTypeId.toString()), thing->id(), ParamList() << valueParam, true);
|
Event event(EventTypeId(stateTypeId.toString()), thing->id(), ParamList() << valueParam, true);
|
||||||
emit eventTriggered(event);
|
emit eventTriggered(event);
|
||||||
|
|
||||||
|
syncIOConnection(thing, stateTypeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThingManagerImplementation::syncIOConnection(Thing *thing, const StateTypeId &stateTypeId)
|
||||||
|
{
|
||||||
|
|
||||||
foreach (const IOConnection &ioConnection, m_ioConnections) {
|
foreach (const IOConnection &ioConnection, m_ioConnections) {
|
||||||
// Check if this state is an input to an IO connection.
|
// Check if this state is an input to an IO connection.
|
||||||
if (ioConnection.inputThingId() == thing->id() && ioConnection.inputStateTypeId() == stateTypeId) {
|
if (ioConnection.inputThingId() == thing->id() && ioConnection.inputStateTypeId() == stateTypeId) {
|
||||||
|
Thing *inputThing = thing;
|
||||||
|
QVariant inputValue = inputThing->stateValue(stateTypeId);
|
||||||
|
|
||||||
Thing *outputThing = m_configuredThings.value(ioConnection.outputThingId());
|
Thing *outputThing = m_configuredThings.value(ioConnection.outputThingId());
|
||||||
if (!outputThing) {
|
if (!outputThing) {
|
||||||
qCWarning(dcThingManager()) << "IO connection contains invalid output thing!";
|
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.";
|
qCWarning(dcThingManager()) << "Plugin not found for IO connection's output action.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
StateType inputStateType = thing->thingClass().getStateType(stateTypeId);
|
StateType inputStateType = inputThing->thingClass().getStateType(stateTypeId);
|
||||||
|
|
||||||
StateType outputStateType = outputThing->thingClass().getStateType(ioConnection.outputStateTypeId());
|
StateType outputStateType = outputThing->thingClass().getStateType(ioConnection.outputStateTypeId());
|
||||||
if (outputStateType.id().isNull()) {
|
if (outputStateType.id().isNull()) {
|
||||||
@ -1759,7 +1773,7 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s
|
|||||||
QVariant outputValue;
|
QVariant outputValue;
|
||||||
if (outputStateType.ioType() == Types::IOTypeDigitalOutput) {
|
if (outputStateType.ioType() == Types::IOTypeDigitalOutput) {
|
||||||
// Digital IOs are mapped as-is
|
// Digital IOs are mapped as-is
|
||||||
outputValue = value;
|
outputValue = ioConnection.inverted() xor inputValue.toBool();
|
||||||
|
|
||||||
// We're already in sync! Skipping action.
|
// We're already in sync! Skipping action.
|
||||||
if (outputThing->stateValue(outputStateType.id()) == outputValue) {
|
if (outputThing->stateValue(outputStateType.id()) == outputValue) {
|
||||||
@ -1767,10 +1781,10 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Analog IOs are mapped within the according min/max ranges
|
// 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.
|
// 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;
|
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
|
// 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.";
|
qCWarning(dcThingManager()) << "Error syncing IO connection state. Reverting input back to old value.";
|
||||||
if (inputStateType.ioType() == Types::IOTypeDigitalInput) {
|
if (inputStateType.ioType() == Types::IOTypeDigitalInput) {
|
||||||
thing->setStateValue(inputStateType.id(), outputThing->stateValue(outputStateType.id()));
|
inputThing->setStateValue(inputStateType.id(), outputThing->stateValue(outputStateType.id()));
|
||||||
} else {
|
} 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
|
// 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) {
|
if (ioConnection.outputThingId() == thing->id() && ioConnection.outputStateTypeId() == stateTypeId) {
|
||||||
|
Thing *outputThing = thing;
|
||||||
|
QVariant outputValue = outputThing->stateValue(stateTypeId);
|
||||||
|
|
||||||
Thing *inputThing = m_configuredThings.value(ioConnection.inputThingId());
|
Thing *inputThing = m_configuredThings.value(ioConnection.inputThingId());
|
||||||
if (!inputThing) {
|
if (!inputThing) {
|
||||||
qCWarning(dcThingManager()) << "IO connection contains invalid input thing!";
|
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.";
|
qCWarning(dcThingManager()) << "Plugin not found for IO connection's input action.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
StateType outputStateType = thing->thingClass().getStateType(stateTypeId);
|
StateType outputStateType = outputThing->thingClass().getStateType(stateTypeId);
|
||||||
|
|
||||||
StateType inputStateType = inputThing->thingClass().getStateType(ioConnection.inputStateTypeId());
|
StateType inputStateType = inputThing->thingClass().getStateType(ioConnection.inputStateTypeId());
|
||||||
if (inputStateType.id().isNull()) {
|
if (inputStateType.id().isNull()) {
|
||||||
@ -1821,7 +1838,7 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s
|
|||||||
QVariant inputValue;
|
QVariant inputValue;
|
||||||
if (inputStateType.ioType() == Types::IOTypeDigitalInput) {
|
if (inputStateType.ioType() == Types::IOTypeDigitalInput) {
|
||||||
// Digital IOs are mapped as-is
|
// Digital IOs are mapped as-is
|
||||||
inputValue = value;
|
inputValue = ioConnection.inverted() xor outputValue.toBool();
|
||||||
|
|
||||||
// Prevent looping
|
// Prevent looping
|
||||||
if (inputThing->stateValue(inputStateType.id()) == inputValue) {
|
if (inputThing->stateValue(inputStateType.id()) == inputValue) {
|
||||||
@ -1829,10 +1846,10 @@ void ThingManagerImplementation::slotThingStateValueChanged(const StateTypeId &s
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Analog IOs are mapped within the according min/max ranges
|
// 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
|
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2000,6 +2017,7 @@ void ThingManagerImplementation::storeIOConnections()
|
|||||||
connectionSettings.setValue("inputStateTypeId", ioConnection.inputStateTypeId().toString());
|
connectionSettings.setValue("inputStateTypeId", ioConnection.inputStateTypeId().toString());
|
||||||
connectionSettings.setValue("outputThingId", ioConnection.outputThingId().toString());
|
connectionSettings.setValue("outputThingId", ioConnection.outputThingId().toString());
|
||||||
connectionSettings.setValue("outputStateTypeId", ioConnection.outputStateTypeId().toString());
|
connectionSettings.setValue("outputStateTypeId", ioConnection.outputStateTypeId().toString());
|
||||||
|
connectionSettings.setValue("inverted", ioConnection.inverted());
|
||||||
|
|
||||||
connectionSettings.endGroup();
|
connectionSettings.endGroup();
|
||||||
}
|
}
|
||||||
@ -2017,14 +2035,15 @@ void ThingManagerImplementation::loadIOConnections()
|
|||||||
StateTypeId inputStateTypeId = connectionSettings.value("inputStateTypeId").toUuid();
|
StateTypeId inputStateTypeId = connectionSettings.value("inputStateTypeId").toUuid();
|
||||||
ThingId outputThingId = connectionSettings.value("outputThingId").toUuid();
|
ThingId outputThingId = connectionSettings.value("outputThingId").toUuid();
|
||||||
StateTypeId outputStateTypeId = connectionSettings.value("outputStateTypeId").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);
|
m_ioConnections.insert(id, ioConnection);
|
||||||
connectionSettings.endGroup();
|
connectionSettings.endGroup();
|
||||||
}
|
}
|
||||||
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 fromMin = fromStateType.minValue().toDouble();
|
||||||
double fromMax = fromStateType.maxValue().toDouble();
|
double fromMax = fromStateType.maxValue().toDouble();
|
||||||
@ -2032,6 +2051,7 @@ QVariant ThingManagerImplementation::mapValue(const QVariant &value, const State
|
|||||||
double toMax = toStateType.maxValue().toDouble();
|
double toMax = toStateType.maxValue().toDouble();
|
||||||
double fromValue = value.toDouble();
|
double fromValue = value.toDouble();
|
||||||
double fromPercent = (fromValue - fromMin) / (fromMax - fromMin);
|
double fromPercent = (fromValue - fromMin) / (fromMax - fromMin);
|
||||||
|
fromPercent = inverted ? 1 - fromPercent : fromPercent;
|
||||||
double toValue = toMin + (toMax - toMin) * fromPercent;
|
double toValue = toMin + (toMax - toMin) * fromPercent;
|
||||||
return toValue;
|
return toValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -157,7 +157,8 @@ private:
|
|||||||
void storeIOConnections();
|
void storeIOConnections();
|
||||||
void loadIOConnections();
|
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:
|
private:
|
||||||
HardwareManager *m_hardwareManager;
|
HardwareManager *m_hardwareManager;
|
||||||
|
|||||||
@ -176,7 +176,7 @@ JsonReply *ActionHandler::ExecuteBrowserItemAction(const QVariantMap ¶ms)
|
|||||||
BrowserItemActionInfo *info = NymeaCore::instance()->executeBrowserItemAction(browserItemAction);
|
BrowserItemActionInfo *info = NymeaCore::instance()->executeBrowserItemAction(browserItemAction);
|
||||||
connect(info, &BrowserItemActionInfo::finished, jsonReply, [info, jsonReply](){
|
connect(info, &BrowserItemActionInfo::finished, jsonReply, [info, jsonReply](){
|
||||||
QVariantMap data;
|
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->setData(data);
|
||||||
jsonReply->finished();
|
jsonReply->finished();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -361,6 +361,7 @@ IntegrationsHandler::IntegrationsHandler(ThingManager *thingManager, QObject *pa
|
|||||||
params.insert("inputStateTypeId", enumValueName(Uuid));
|
params.insert("inputStateTypeId", enumValueName(Uuid));
|
||||||
params.insert("outputThingId", enumValueName(Uuid));
|
params.insert("outputThingId", enumValueName(Uuid));
|
||||||
params.insert("outputStateTypeId", enumValueName(Uuid));
|
params.insert("outputStateTypeId", enumValueName(Uuid));
|
||||||
|
params.insert("o:inverted", enumValueName(Bool));
|
||||||
returns.insert("thingError", enumRef<Thing::ThingError>());
|
returns.insert("thingError", enumRef<Thing::ThingError>());
|
||||||
returns.insert("o:ioConnectionId", enumValueName(Uuid));
|
returns.insert("o:ioConnectionId", enumValueName(Uuid));
|
||||||
registerMethod("ConnectIO", description, params, returns);
|
registerMethod("ConnectIO", description, params, returns);
|
||||||
@ -992,7 +993,8 @@ JsonReply *IntegrationsHandler::ConnectIO(const QVariantMap ¶ms)
|
|||||||
StateTypeId inputStateTypeId = params.value("inputStateTypeId").toUuid();
|
StateTypeId inputStateTypeId = params.value("inputStateTypeId").toUuid();
|
||||||
ThingId outputThingId = params.value("outputThingId").toUuid();
|
ThingId outputThingId = params.value("outputThingId").toUuid();
|
||||||
StateTypeId outputStateTypeId = params.value("outputStateTypeId").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);
|
QVariantMap reply = statusToReply(result.error);
|
||||||
if (result.error == Thing::ThingErrorNoError) {
|
if (result.error == Thing::ThingErrorNoError) {
|
||||||
reply.insert("ioConnectionId", result.ioConnectionId);
|
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_id(id),
|
||||||
m_inputThingId(inputThing),
|
m_inputThingId(inputThing),
|
||||||
m_inputStateTypeId(inputState),
|
m_inputStateTypeId(inputState),
|
||||||
m_outputThingId(outputThing),
|
m_outputThingId(outputThing),
|
||||||
m_outputStateTypeId(outputState)
|
m_outputStateTypeId(outputState),
|
||||||
|
m_inverted(inverted)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -40,6 +41,11 @@ StateTypeId IOConnection::outputStateTypeId() const
|
|||||||
return m_outputStateTypeId;
|
return m_outputStateTypeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IOConnection::inverted() const
|
||||||
|
{
|
||||||
|
return m_inverted;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant IOConnections::get(int index) const
|
QVariant IOConnections::get(int index) const
|
||||||
{
|
{
|
||||||
return QVariant::fromValue(at(index));
|
return QVariant::fromValue(at(index));
|
||||||
|
|||||||
@ -21,10 +21,11 @@ class IOConnection
|
|||||||
Q_PROPERTY(QUuid inputStateTypeId READ inputStateTypeId)
|
Q_PROPERTY(QUuid inputStateTypeId READ inputStateTypeId)
|
||||||
Q_PROPERTY(QUuid outputThingId READ outputThingId)
|
Q_PROPERTY(QUuid outputThingId READ outputThingId)
|
||||||
Q_PROPERTY(QUuid outputStateTypeId READ outputStateTypeId)
|
Q_PROPERTY(QUuid outputStateTypeId READ outputStateTypeId)
|
||||||
|
Q_PROPERTY(bool inverted READ inverted)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IOConnection();
|
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;
|
IOConnectionId id() const;
|
||||||
|
|
||||||
@ -34,12 +35,15 @@ public:
|
|||||||
ThingId outputThingId() const;
|
ThingId outputThingId() const;
|
||||||
StateTypeId outputStateTypeId() const;
|
StateTypeId outputStateTypeId() const;
|
||||||
|
|
||||||
|
bool inverted() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IOConnectionId m_id;
|
IOConnectionId m_id;
|
||||||
ThingId m_inputThingId;
|
ThingId m_inputThingId;
|
||||||
StateTypeId m_inputStateTypeId;
|
StateTypeId m_inputStateTypeId;
|
||||||
ThingId m_outputThingId;
|
ThingId m_outputThingId;
|
||||||
StateTypeId m_outputStateTypeId;
|
StateTypeId m_outputStateTypeId;
|
||||||
|
bool m_inverted = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IOConnections: public QList<IOConnection>
|
class IOConnections: public QList<IOConnection>
|
||||||
|
|||||||
@ -51,8 +51,8 @@ ThingManager::ThingManager(QObject *parent) : QObject(parent)
|
|||||||
qRegisterMetaType<ParamTypes>();
|
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);
|
return connectIO(connection);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,7 +91,7 @@ public:
|
|||||||
virtual BrowserItemActionInfo* executeBrowserItemAction(const BrowserItemAction &browserItemAction) = 0;
|
virtual BrowserItemActionInfo* executeBrowserItemAction(const BrowserItemAction &browserItemAction) = 0;
|
||||||
|
|
||||||
virtual IOConnections ioConnections(const ThingId &thingId = ThingId()) const = 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 Thing::ThingError disconnectIO(const IOConnectionId &ioConnectionId) = 0;
|
||||||
|
|
||||||
virtual QString translate(const PluginId &pluginId, const QString &string, const QLocale &locale) = 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->thing()->thingClassId() == virtualIoTemperatureSensorMockThingClassId) {
|
||||||
if (info->action().actionTypeId() == virtualIoTemperatureSensorMockInputActionTypeId) {
|
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 minTemp = info->thing()->setting(virtualIoTemperatureSensorMockSettingsMinTempParamTypeId).toDouble();
|
||||||
double maxTemp = info->thing()->setting(virtualIoTemperatureSensorMockSettingsMaxTempParamTypeId).toDouble();
|
double maxTemp = info->thing()->setting(virtualIoTemperatureSensorMockSettingsMaxTempParamTypeId).toDouble();
|
||||||
double value = info->action().param(virtualIoTemperatureSensorMockInputActionInputParamTypeId).value().toDouble();
|
|
||||||
double temp = minTemp + (maxTemp - minTemp) * value;
|
double temp = minTemp + (maxTemp - minTemp) * value;
|
||||||
qCDebug(dcMock()) << "Min:" << minTemp << "Max:" << maxTemp << "value:" << value << "temp:" << temp;
|
|
||||||
info->thing()->setStateValue(virtualIoTemperatureSensorMockTemperatureStateTypeId, temp);
|
info->thing()->setStateValue(virtualIoTemperatureSensorMockTemperatureStateTypeId, temp);
|
||||||
info->finish(Thing::ThingErrorNoError);
|
info->finish(Thing::ThingErrorNoError);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -1035,7 +1035,7 @@
|
|||||||
"displayNameEvent": "Temperature changed",
|
"displayNameEvent": "Temperature changed",
|
||||||
"type": "double",
|
"type": "double",
|
||||||
"unit": "DegreeCelsius",
|
"unit": "DegreeCelsius",
|
||||||
"defaultValue": 0
|
"defaultValue": -20
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -949,6 +949,7 @@
|
|||||||
"params": {
|
"params": {
|
||||||
"inputStateTypeId": "Uuid",
|
"inputStateTypeId": "Uuid",
|
||||||
"inputThingId": "Uuid",
|
"inputThingId": "Uuid",
|
||||||
|
"o:inverted": "Bool",
|
||||||
"outputStateTypeId": "Uuid",
|
"outputStateTypeId": "Uuid",
|
||||||
"outputThingId": "Uuid"
|
"outputThingId": "Uuid"
|
||||||
},
|
},
|
||||||
@ -2456,6 +2457,7 @@
|
|||||||
"r:id": "Uuid",
|
"r:id": "Uuid",
|
||||||
"r:inputStateTypeId": "Uuid",
|
"r:inputStateTypeId": "Uuid",
|
||||||
"r:inputThingId": "Uuid",
|
"r:inputThingId": "Uuid",
|
||||||
|
"r:inverted": "Bool",
|
||||||
"r:outputStateTypeId": "Uuid",
|
"r:outputStateTypeId": "Uuid",
|
||||||
"r:outputThingId": "Uuid"
|
"r:outputThingId": "Uuid"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -60,8 +60,10 @@ private slots:
|
|||||||
void testConnectionCompatibility_data();
|
void testConnectionCompatibility_data();
|
||||||
void testConnectionCompatibility();
|
void testConnectionCompatibility();
|
||||||
|
|
||||||
|
void testDigitalIO_data();
|
||||||
void testDigitalIO();
|
void testDigitalIO();
|
||||||
|
|
||||||
|
void testAnalogIO_data();
|
||||||
void testAnalogIO();
|
void testAnalogIO();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -71,6 +73,7 @@ void TestIOConnections::initTestCase()
|
|||||||
QLoggingCategory::setFilterRules("*.debug=false\n"
|
QLoggingCategory::setFilterRules("*.debug=false\n"
|
||||||
"Tests.debug=true\n"
|
"Tests.debug=true\n"
|
||||||
"Mock.debug=true\n"
|
"Mock.debug=true\n"
|
||||||
|
"ThingManager.debug=true\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Adding generic IO mock
|
// 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()
|
void TestIOConnections::testDigitalIO()
|
||||||
{
|
{
|
||||||
|
QFETCH(bool, inverted);
|
||||||
|
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("inputThingId", m_lightThingId);
|
params.insert("inputThingId", m_lightThingId);
|
||||||
params.insert("inputStateTypeId", virtualIoLightMockPowerStateTypeId);
|
params.insert("inputStateTypeId", virtualIoLightMockPowerStateTypeId);
|
||||||
params.insert("outputThingId", m_ioThingId);
|
params.insert("outputThingId", m_ioThingId);
|
||||||
params.insert("outputStateTypeId", genericIoMockDigitalOutput1StateTypeId);
|
params.insert("outputStateTypeId", genericIoMockDigitalOutput1StateTypeId);
|
||||||
|
params.insert("inverted", inverted);
|
||||||
QVariant response = injectAndWait("Integrations.ConnectIO", params);
|
QVariant response = injectAndWait("Integrations.ConnectIO", params);
|
||||||
verifyThingError(response);
|
verifyThingError(response);
|
||||||
IOConnectionId ioConnectionId = response.toMap().value("params").toMap().value("ioConnectionId").toUuid();
|
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.clear();
|
||||||
params.insert("thingId", m_lightThingId);
|
params.insert("thingId", m_lightThingId);
|
||||||
params.insert("stateTypeId", virtualIoLightMockPowerStateTypeId);
|
params.insert("stateTypeId", virtualIoLightMockPowerStateTypeId);
|
||||||
response = injectAndWait("Integrations.GetStateValue", params);
|
response = injectAndWait("Integrations.GetStateValue", params);
|
||||||
verifyThingError(response);
|
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.clear();
|
||||||
params.insert("thingId", m_ioThingId);
|
params.insert("thingId", m_ioThingId);
|
||||||
params.insert("stateTypeId", genericIoMockDigitalOutput1StateTypeId);
|
params.insert("stateTypeId", genericIoMockDigitalOutput1StateTypeId);
|
||||||
response = injectAndWait("Integrations.GetStateValue", params);
|
response = injectAndWait("Integrations.GetStateValue", params);
|
||||||
verifyThingError(response);
|
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
|
// Turn on light and verify digital output went on
|
||||||
|
expectedValue = true;
|
||||||
params.clear();
|
params.clear();
|
||||||
params.insert("thingId", m_lightThingId);
|
params.insert("thingId", m_lightThingId);
|
||||||
params.insert("actionTypeId", virtualIoLightMockPowerActionTypeId);
|
params.insert("actionTypeId", virtualIoLightMockPowerActionTypeId);
|
||||||
@ -193,7 +210,7 @@ void TestIOConnections::testDigitalIO()
|
|||||||
params.insert("stateTypeId", genericIoMockDigitalOutput1StateTypeId);
|
params.insert("stateTypeId", genericIoMockDigitalOutput1StateTypeId);
|
||||||
response = injectAndWait("Integrations.GetStateValue", params);
|
response = injectAndWait("Integrations.GetStateValue", params);
|
||||||
verifyThingError(response);
|
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
|
// Disconnect IO again
|
||||||
params.clear();
|
params.clear();
|
||||||
@ -202,6 +219,7 @@ void TestIOConnections::testDigitalIO()
|
|||||||
verifyThingError(response);
|
verifyThingError(response);
|
||||||
|
|
||||||
// Turn off the light and verify digital output is still on
|
// Turn off the light and verify digital output is still on
|
||||||
|
expectedValue = true;
|
||||||
params.clear();
|
params.clear();
|
||||||
params.insert("thingId", m_lightThingId);
|
params.insert("thingId", m_lightThingId);
|
||||||
params.insert("actionTypeId", virtualIoLightMockPowerActionTypeId);
|
params.insert("actionTypeId", virtualIoLightMockPowerActionTypeId);
|
||||||
@ -217,41 +235,59 @@ void TestIOConnections::testDigitalIO()
|
|||||||
params.insert("stateTypeId", genericIoMockDigitalOutput1StateTypeId);
|
params.insert("stateTypeId", genericIoMockDigitalOutput1StateTypeId);
|
||||||
response = injectAndWait("Integrations.GetStateValue", params);
|
response = injectAndWait("Integrations.GetStateValue", params);
|
||||||
verifyThingError(response);
|
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()
|
void TestIOConnections::testAnalogIO()
|
||||||
{
|
{
|
||||||
|
QFETCH(bool, inverted);
|
||||||
|
|
||||||
|
// Set input to 0
|
||||||
QVariantMap params;
|
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("inputThingId", m_ioThingId);
|
||||||
params.insert("inputStateTypeId", genericIoMockAnalogInput1StateTypeId);
|
params.insert("inputStateTypeId", genericIoMockAnalogInput1StateTypeId);
|
||||||
params.insert("outputThingId", m_tempSensorThingId);
|
params.insert("outputThingId", m_tempSensorThingId);
|
||||||
params.insert("outputStateTypeId", virtualIoTemperatureSensorMockInputStateTypeId);
|
params.insert("outputStateTypeId", virtualIoTemperatureSensorMockInputStateTypeId);
|
||||||
QVariant response = injectAndWait("Integrations.ConnectIO", params);
|
params.insert("inverted", inverted);
|
||||||
|
|
||||||
|
response = injectAndWait("Integrations.ConnectIO", params);
|
||||||
verifyThingError(response);
|
verifyThingError(response);
|
||||||
IOConnectionId ioConnectionId = response.toMap().value("params").toMap().value("ioConnectionId").toUuid();
|
IOConnectionId ioConnectionId = response.toMap().value("params").toMap().value("ioConnectionId").toUuid();
|
||||||
|
|
||||||
// verify input is at 0, temp at 0 too
|
// and check temp senser
|
||||||
params.clear();
|
double expectedTemp = inverted ? 50 : -20;
|
||||||
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");
|
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.insert("thingId", m_tempSensorThingId);
|
params.insert("thingId", m_tempSensorThingId);
|
||||||
params.insert("stateTypeId", virtualIoTemperatureSensorMockTemperatureStateTypeId);
|
params.insert("stateTypeId", virtualIoTemperatureSensorMockTemperatureStateTypeId);
|
||||||
response = injectAndWait("Integrations.GetStateValue", params);
|
response = injectAndWait("Integrations.GetStateValue", params);
|
||||||
verifyThingError(response);
|
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
|
// set analog input to 0.5 and verify temp aligned
|
||||||
params.clear();
|
params.clear();
|
||||||
params.insert("thingId", m_ioThingId);
|
params.insert("thingId", m_ioThingId);
|
||||||
params.insert("actionTypeId", genericIoMockAnalogInput1StateTypeId);
|
params.insert("actionTypeId", genericIoMockAnalogInput1StateTypeId);
|
||||||
QVariantMap actionParam;
|
actionParam.clear();
|
||||||
actionParam.insert("paramTypeId", genericIoMockAnalogInput1ActionAnalogInput1ParamTypeId);
|
actionParam.insert("paramTypeId", genericIoMockAnalogInput1ActionAnalogInput1ParamTypeId);
|
||||||
actionParam.insert("value", 1.65); // goes from 0 to 3.3
|
actionParam.insert("value", 1.65); // goes from 0 to 3.3
|
||||||
params.insert("params", QVariantList() << actionParam);
|
params.insert("params", QVariantList() << actionParam);
|
||||||
@ -265,7 +301,7 @@ void TestIOConnections::testAnalogIO()
|
|||||||
verifyThingError(response);
|
verifyThingError(response);
|
||||||
// generic IO output goes from 0 to 3.3. We're setting 1.65V which 50%
|
// 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
|
// 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());
|
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
|
// Disconnect IO again
|
||||||
|
|||||||
Reference in New Issue
Block a user