diff --git a/libnymea/interfaces/interfaces.qrc b/libnymea/interfaces/interfaces.qrc index 00c41b34..4e6c2c0f 100644 --- a/libnymea/interfaces/interfaces.qrc +++ b/libnymea/interfaces/interfaces.qrc @@ -82,5 +82,6 @@ barcodescanner.json irrigation.json venetianblind.json + update.json diff --git a/libnymea/interfaces/update.json b/libnymea/interfaces/update.json new file mode 100644 index 00000000..191f21f8 --- /dev/null +++ b/libnymea/interfaces/update.json @@ -0,0 +1,24 @@ +{ + "description": "The update interface is used for things that support being updated by nymea.", + "states": [ + { + "name": "updateStatus", + "type": "QString", + "allowedValues": ["idle", "available", "updating"] + }, + { + "name": "currentVersion", + "type": "QString" + }, + { + "name": "availableVersion", + "type": "QString", + "optional": true + } + ], + "actions": [ + { + "name": "performUpdate" + } + ] +} diff --git a/plugins/mock/extern-plugininfo.h b/plugins/mock/extern-plugininfo.h index 5e440489..b7ba912a 100644 --- a/plugins/mock/extern-plugininfo.h +++ b/plugins/mock/extern-plugininfo.h @@ -28,6 +28,9 @@ extern StateTypeId mockBatteryCriticalStateTypeId; extern StateTypeId mockPowerStateTypeId; extern StateTypeId mockConnectedStateTypeId; extern StateTypeId mockSignalStrengthStateTypeId; +extern StateTypeId mockUpdateStatusStateTypeId; +extern StateTypeId mockCurrentVersionStateTypeId; +extern StateTypeId mockAvailableVersionStateTypeId; extern EventTypeId mockIntEventTypeId; extern ParamTypeId mockIntEventIntParamTypeId; extern EventTypeId mockBoolEventTypeId; @@ -44,6 +47,12 @@ extern EventTypeId mockConnectedEventTypeId; extern ParamTypeId mockConnectedEventConnectedParamTypeId; extern EventTypeId mockSignalStrengthEventTypeId; extern ParamTypeId mockSignalStrengthEventSignalStrengthParamTypeId; +extern EventTypeId mockUpdateStatusEventTypeId; +extern ParamTypeId mockUpdateStatusEventUpdateStatusParamTypeId; +extern EventTypeId mockCurrentVersionEventTypeId; +extern ParamTypeId mockCurrentVersionEventCurrentVersionParamTypeId; +extern EventTypeId mockAvailableVersionEventTypeId; +extern ParamTypeId mockAvailableVersionEventAvailableVersionParamTypeId; extern EventTypeId mockEvent1EventTypeId; extern EventTypeId mockEvent2EventTypeId; extern ParamTypeId mockEvent2EventIntParamParamTypeId; @@ -53,6 +62,8 @@ extern ActionTypeId mockPowerActionTypeId; extern ParamTypeId mockPowerActionPowerParamTypeId; extern ActionTypeId mockSignalStrengthActionTypeId; extern ParamTypeId mockSignalStrengthActionSignalStrengthParamTypeId; +extern ActionTypeId mockUpdateStatusActionTypeId; +extern ParamTypeId mockUpdateStatusActionUpdateStatusParamTypeId; extern ActionTypeId mockWithParamsActionTypeId; extern ParamTypeId mockWithParamsActionParam1ParamTypeId; extern ParamTypeId mockWithParamsActionParam2ParamTypeId; @@ -60,6 +71,7 @@ extern ActionTypeId mockWithoutParamsActionTypeId; extern ActionTypeId mockAsyncActionTypeId; extern ActionTypeId mockFailingActionTypeId; extern ActionTypeId mockAsyncFailingActionTypeId; +extern ActionTypeId mockPerformUpdateActionTypeId; extern ActionTypeId mockAddToFavoritesBrowserItemActionTypeId; extern ActionTypeId mockRemoveFromFavoritesBrowserItemActionTypeId; extern ThingClassId autoMockThingClassId; diff --git a/plugins/mock/integrationpluginmock.cpp b/plugins/mock/integrationpluginmock.cpp index a689378d..06675fb1 100644 --- a/plugins/mock/integrationpluginmock.cpp +++ b/plugins/mock/integrationpluginmock.cpp @@ -585,6 +585,13 @@ void IntegrationPluginMock::executeAction(ThingActionInfo *info) info->thing()->setStateValue(mockSignalStrengthStateTypeId, newStrength); info->thing()->setStateValue(mockConnectedStateTypeId, newStrength != 0); } + + if (info->action().actionTypeId() == mockUpdateStatusActionTypeId) { + QString newUpdateStatus = info->action().param(mockUpdateStatusActionUpdateStatusParamTypeId).value().toString(); + qCDebug(dcMock()) << "Setting update status to" << newUpdateStatus; + info->thing()->setStateValue(mockUpdateStatusStateTypeId, newUpdateStatus); + info->thing()->setStateValue(mockAvailableVersionStateTypeId, newUpdateStatus == "available" ? "2.0" : "1.0"); + } m_daemons.value(info->thing())->actionExecuted(info->action().actionTypeId()); info->finish(Thing::ThingErrorNoError); return; diff --git a/plugins/mock/integrationpluginmock.json b/plugins/mock/integrationpluginmock.json index 095389d1..c3afe9e9 100644 --- a/plugins/mock/integrationpluginmock.json +++ b/plugins/mock/integrationpluginmock.json @@ -30,7 +30,7 @@ "id": "753f0d32-0468-4d08-82ed-1964aab03298", "name": "mock", "displayName": "Mock Thing", - "interfaces": ["system", "light", "batterylevel", "wirelessconnectable"], + "interfaces": ["system", "light", "batterylevel", "wirelessconnectable", "update"], "createMethods": ["user", "discovery"], "browsable": true, "discoveryParamTypes": [ @@ -153,6 +153,33 @@ "maxValue": 100, "defaultValue": 50, "writable": true + }, + { + "id": "ebc41327-53d5-40c2-8e7b-1164a8ff359e", + "name": "updateStatus", + "displayName": "Update status", + "displayNameEvent": "Update status changed", + "displayNameAction": "Set update status", + "type": "QString", + "possibleValues": ["idle", "available", "updating"], + "defaultValue": "idle", + "writable": true + }, + { + "id": "9f2e1e5d-3f1f-4794-aca3-4e05b7a48842", + "name": "currentVersion", + "displayName": "Firmware version", + "displayNameEvent": "Firmware version changed", + "type": "QString", + "defaultValue": "" + }, + { + "id": "060d7947-2b70-4a2b-b33b-a3577f71faeb", + "name": "availableVersion", + "displayName": "Available firmware version", + "displayNameEvent": "Available firmware version changed", + "type": "QString", + "defaultValue": "" } ], "eventTypes": [ @@ -215,6 +242,11 @@ "id": "bfe89a1d-3497-4121-8318-e77c37537219", "name": "asyncFailing", "displayName": "Mock Action 5 (async, broken)" + }, + { + "id": "f2b847dd-ab40-4278-940b-3615f1d7dfd3", + "name": "performUpdate", + "displayName": "Update firmware" } ], "browserItemActionTypes": [ diff --git a/plugins/mock/plugininfo.h b/plugins/mock/plugininfo.h index 002d9b16..255a6ea8 100644 --- a/plugins/mock/plugininfo.h +++ b/plugins/mock/plugininfo.h @@ -32,6 +32,9 @@ StateTypeId mockBatteryCriticalStateTypeId = StateTypeId("{580bc611-1a55-41f3-99 StateTypeId mockPowerStateTypeId = StateTypeId("{064aed0d-da4c-49d4-b236-60f97e98ff84}"); StateTypeId mockConnectedStateTypeId = StateTypeId("{9860d105-2bd9-4651-9bc9-13ff4b9039a7}"); StateTypeId mockSignalStrengthStateTypeId = StateTypeId("{2a0213bf-4af3-4384-904e-3376348a597e}"); +StateTypeId mockUpdateStatusStateTypeId = StateTypeId("{ebc41327-53d5-40c2-8e7b-1164a8ff359e}"); +StateTypeId mockCurrentVersionStateTypeId = StateTypeId("{9f2e1e5d-3f1f-4794-aca3-4e05b7a48842}"); +StateTypeId mockAvailableVersionStateTypeId = StateTypeId("{060d7947-2b70-4a2b-b33b-a3577f71faeb}"); EventTypeId mockIntEventTypeId = EventTypeId("{80baec19-54de-4948-ac46-31eabfaceb83}"); ParamTypeId mockIntEventIntParamTypeId = ParamTypeId("{80baec19-54de-4948-ac46-31eabfaceb83}"); EventTypeId mockBoolEventTypeId = EventTypeId("{9dd6a97c-dfd1-43dc-acbd-367932742310}"); @@ -48,6 +51,12 @@ EventTypeId mockConnectedEventTypeId = EventTypeId("{9860d105-2bd9-4651-9bc9-13f ParamTypeId mockConnectedEventConnectedParamTypeId = ParamTypeId("{9860d105-2bd9-4651-9bc9-13ff4b9039a7}"); EventTypeId mockSignalStrengthEventTypeId = EventTypeId("{2a0213bf-4af3-4384-904e-3376348a597e}"); ParamTypeId mockSignalStrengthEventSignalStrengthParamTypeId = ParamTypeId("{2a0213bf-4af3-4384-904e-3376348a597e}"); +EventTypeId mockUpdateStatusEventTypeId = EventTypeId("{ebc41327-53d5-40c2-8e7b-1164a8ff359e}"); +ParamTypeId mockUpdateStatusEventUpdateStatusParamTypeId = ParamTypeId("{ebc41327-53d5-40c2-8e7b-1164a8ff359e}"); +EventTypeId mockCurrentVersionEventTypeId = EventTypeId("{9f2e1e5d-3f1f-4794-aca3-4e05b7a48842}"); +ParamTypeId mockCurrentVersionEventCurrentVersionParamTypeId = ParamTypeId("{9f2e1e5d-3f1f-4794-aca3-4e05b7a48842}"); +EventTypeId mockAvailableVersionEventTypeId = EventTypeId("{060d7947-2b70-4a2b-b33b-a3577f71faeb}"); +ParamTypeId mockAvailableVersionEventAvailableVersionParamTypeId = ParamTypeId("{060d7947-2b70-4a2b-b33b-a3577f71faeb}"); EventTypeId mockEvent1EventTypeId = EventTypeId("{45bf3752-0fc6-46b9-89fd-ffd878b5b22b}"); EventTypeId mockEvent2EventTypeId = EventTypeId("{863d5920-b1cf-4eb9-88bd-8f7b8583b1cf}"); ParamTypeId mockEvent2EventIntParamParamTypeId = ParamTypeId("{0550e16d-60b9-4ba5-83f4-4d3cee656121}"); @@ -57,6 +66,8 @@ ActionTypeId mockPowerActionTypeId = ActionTypeId("{064aed0d-da4c-49d4-b236-60f9 ParamTypeId mockPowerActionPowerParamTypeId = ParamTypeId("{064aed0d-da4c-49d4-b236-60f97e98ff84}"); ActionTypeId mockSignalStrengthActionTypeId = ActionTypeId("{2a0213bf-4af3-4384-904e-3376348a597e}"); ParamTypeId mockSignalStrengthActionSignalStrengthParamTypeId = ParamTypeId("{2a0213bf-4af3-4384-904e-3376348a597e}"); +ActionTypeId mockUpdateStatusActionTypeId = ActionTypeId("{ebc41327-53d5-40c2-8e7b-1164a8ff359e}"); +ParamTypeId mockUpdateStatusActionUpdateStatusParamTypeId = ParamTypeId("{ebc41327-53d5-40c2-8e7b-1164a8ff359e}"); ActionTypeId mockWithParamsActionTypeId = ActionTypeId("{dea0f4e1-65e3-4981-8eaa-2701c53a9185}"); ParamTypeId mockWithParamsActionParam1ParamTypeId = ParamTypeId("{a2d3a256-a551-4712-a65b-ecd5a436a1cb}"); ParamTypeId mockWithParamsActionParam2ParamTypeId = ParamTypeId("{304a4899-18be-4e3b-94f4-d03be52f3233}"); @@ -64,6 +75,7 @@ ActionTypeId mockWithoutParamsActionTypeId = ActionTypeId("{defd3ed6-1a0d-400b-8 ActionTypeId mockAsyncActionTypeId = ActionTypeId("{fbae06d3-7666-483e-a39e-ec50fe89054e}"); ActionTypeId mockFailingActionTypeId = ActionTypeId("{df3cf33d-26d5-4577-9132-9823bd33fad0}"); ActionTypeId mockAsyncFailingActionTypeId = ActionTypeId("{bfe89a1d-3497-4121-8318-e77c37537219}"); +ActionTypeId mockPerformUpdateActionTypeId = ActionTypeId("{f2b847dd-ab40-4278-940b-3615f1d7dfd3}"); ActionTypeId mockAddToFavoritesBrowserItemActionTypeId = ActionTypeId("{00b8f0a8-99ca-4aa4-833d-59eb8d4d6de3}"); ActionTypeId mockRemoveFromFavoritesBrowserItemActionTypeId = ActionTypeId("{da6faef8-2816-430e-93bb-57e8f9582d29}"); ThingClassId autoMockThingClassId = ThingClassId("{ab4257b3-7548-47ee-9bd4-7dc3004fd197}"); @@ -363,6 +375,15 @@ const QString translations[] { //: The name of the EventType ({e40bcf7d-47b8-41fa-b213-3652a905b376}) of ThingClass genericIoMock QT_TRANSLATE_NOOP("mock", "Analog Output 2 changed"), + //: The name of the ParamType (ThingClass: mock, EventType: availableVersion, ID: {060d7947-2b70-4a2b-b33b-a3577f71faeb}) + QT_TRANSLATE_NOOP("mock", "Available firmware version"), + + //: The name of the StateType ({060d7947-2b70-4a2b-b33b-a3577f71faeb}) of ThingClass mock + QT_TRANSLATE_NOOP("mock", "Available firmware version"), + + //: The name of the EventType ({060d7947-2b70-4a2b-b33b-a3577f71faeb}) of ThingClass mock + QT_TRANSLATE_NOOP("mock", "Available firmware version changed"), + //: The name of the ParamType (ThingClass: mock, ActionType: batteryLevel, ID: {6c8ab9a6-0164-4795-b829-f4394fe4edc4}) QT_TRANSLATE_NOOP("mock", "Battery level"), @@ -498,6 +519,15 @@ const QString translations[] { //: The name of the EventType ({80baec19-54de-4948-ac46-31eabfaceb83}) of ThingClass mock QT_TRANSLATE_NOOP("mock", "Dummy int state changed"), + //: The name of the ParamType (ThingClass: mock, EventType: currentVersion, ID: {9f2e1e5d-3f1f-4794-aca3-4e05b7a48842}) + QT_TRANSLATE_NOOP("mock", "Firmware version"), + + //: The name of the StateType ({9f2e1e5d-3f1f-4794-aca3-4e05b7a48842}) of ThingClass mock + QT_TRANSLATE_NOOP("mock", "Firmware version"), + + //: The name of the EventType ({9f2e1e5d-3f1f-4794-aca3-4e05b7a48842}) of ThingClass mock + QT_TRANSLATE_NOOP("mock", "Firmware version changed"), + //: The name of the ThingClass ({7cbd729a-465b-4ccb-b59c-5733039dbbed}) QT_TRANSLATE_NOOP("mock", "Generic IO pins"), @@ -747,6 +777,9 @@ const QString translations[] { //: The name of the ActionType ({2a0213bf-4af3-4384-904e-3376348a597e}) of ThingClass mock QT_TRANSLATE_NOOP("mock", "Set signal strength"), + //: The name of the ActionType ({ebc41327-53d5-40c2-8e7b-1164a8ff359e}) of ThingClass mock + QT_TRANSLATE_NOOP("mock", "Set update status"), + //: The name of the ParamType (ThingClass: mock, Type: settings, ID: {367f7ba4-5039-47be-abd8-59cc8eaf4b9a}) QT_TRANSLATE_NOOP("mock", "Setting 1"), @@ -831,6 +864,21 @@ const QString translations[] { //: The name of the ParamType (ThingClass: inputTypeMock, Type: thing, ID: {fa67229f-fcef-496f-b671-59a4b48f3ab5}) QT_TRANSLATE_NOOP("mock", "URL"), + //: The name of the ActionType ({f2b847dd-ab40-4278-940b-3615f1d7dfd3}) of ThingClass mock + QT_TRANSLATE_NOOP("mock", "Update firmware"), + + //: The name of the ParamType (ThingClass: mock, ActionType: updateStatus, ID: {ebc41327-53d5-40c2-8e7b-1164a8ff359e}) + QT_TRANSLATE_NOOP("mock", "Update status"), + + //: The name of the ParamType (ThingClass: mock, EventType: updateStatus, ID: {ebc41327-53d5-40c2-8e7b-1164a8ff359e}) + QT_TRANSLATE_NOOP("mock", "Update status"), + + //: The name of the StateType ({ebc41327-53d5-40c2-8e7b-1164a8ff359e}) of ThingClass mock + QT_TRANSLATE_NOOP("mock", "Update status"), + + //: The name of the EventType ({ebc41327-53d5-40c2-8e7b-1164a8ff359e}) of ThingClass mock + QT_TRANSLATE_NOOP("mock", "Update status changed"), + //: The name of the ParamType (ThingClass: inputTypeMock, ActionType: writableBool, ID: {a7c11774-f31f-4d64-99d1-e0ae5fb35a5c}) QT_TRANSLATE_NOOP("mock", "Writable Bool"), diff --git a/tests/auto/devices/testdevices.cpp b/tests/auto/devices/testdevices.cpp index d4557eb9..b7cf86fa 100644 --- a/tests/auto/devices/testdevices.cpp +++ b/tests/auto/devices/testdevices.cpp @@ -327,7 +327,7 @@ void TestDevices::verifyInterfaces() QVERIFY(!mockDevice.isEmpty()); QVariantList interfaces = mockDevice.value("interfaces").toList(); - QVariantList expectedInterfaces = {"system", "light", "power", "batterylevel", "battery", "wirelesssignalstrength", "wirelessconnectable", "connectable"}; + QVariantList expectedInterfaces = {"system", "light", "power", "batterylevel", "battery", "wirelessconnectable", "connectable", "update"}; qCDebug(dcTests()) << interfaces; qCDebug(dcTests()) << expectedInterfaces; QCOMPARE(interfaces, expectedInterfaces); @@ -896,7 +896,7 @@ void TestDevices::getActionTypes_data() QTest::addColumn >("actionTypeTestData"); QTest::newRow("valid deviceclass") << mockThingClassId - << (QList() << mockAsyncActionTypeId << mockAsyncFailingActionTypeId << mockFailingActionTypeId << mockWithoutParamsActionTypeId << mockPowerActionTypeId << mockWithoutParamsActionTypeId << mockBatteryLevelActionTypeId << mockSignalStrengthActionTypeId); + << (QList() << mockAsyncActionTypeId << mockAsyncFailingActionTypeId << mockFailingActionTypeId << mockWithoutParamsActionTypeId << mockPowerActionTypeId << mockWithoutParamsActionTypeId << mockBatteryLevelActionTypeId << mockSignalStrengthActionTypeId << mockUpdateStatusActionTypeId << mockPerformUpdateActionTypeId); QTest::newRow("invalid deviceclass") << ThingClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << QList(); } @@ -928,7 +928,7 @@ void TestDevices::getEventTypes_data() QTest::addColumn("deviceClassId"); QTest::addColumn("resultCount"); - QTest::newRow("valid deviceclass") << mockThingClassId << 10; + QTest::newRow("valid deviceclass") << mockThingClassId << 13; QTest::newRow("invalid deviceclass") << ThingClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0; } @@ -953,7 +953,7 @@ void TestDevices::getStateTypes_data() QTest::addColumn("thingClassId"); QTest::addColumn("resultCount"); - QTest::newRow("valid deviceclass") << mockThingClassId << 8; + QTest::newRow("valid deviceclass") << mockThingClassId << 11; QTest::newRow("invalid deviceclass") << ThingClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0; } @@ -1052,7 +1052,7 @@ void TestDevices::getStateValues() QCOMPARE(response.toMap().value("params").toMap().value("deviceError").toString(), enumValueName(statusCode)); if (statusCode == Device::DeviceErrorNoError) { QVariantList values = response.toMap().value("params").toMap().value("values").toList(); - QCOMPARE(values.count(), 8); // Mock device has 8 states... + QCOMPARE(values.count(), 11); // Mock device has 11 states... } } diff --git a/tests/auto/integrations/testintegrations.cpp b/tests/auto/integrations/testintegrations.cpp index d18077af..1cc11d7c 100644 --- a/tests/auto/integrations/testintegrations.cpp +++ b/tests/auto/integrations/testintegrations.cpp @@ -327,7 +327,7 @@ void TestIntegrations::verifyInterfaces() QVERIFY(!mock.isEmpty()); QVariantList interfaces = mock.value("interfaces").toList(); - QVariantList expectedInterfaces = {"system", "light", "power", "batterylevel", "battery", "wirelesssignalstrength", "wirelessconnectable", "connectable"}; + QVariantList expectedInterfaces = {"system", "light", "power", "batterylevel", "battery", "wirelessconnectable", "connectable", "update"}; qCDebug(dcTests()) << interfaces; qCDebug(dcTests()) << expectedInterfaces; QCOMPARE(interfaces, expectedInterfaces); @@ -894,7 +894,7 @@ void TestIntegrations::getActionTypes_data() QTest::addColumn >("actionTypeTestData"); QTest::newRow("valid thingClass") << mockThingClassId - << (QList() << mockAsyncActionTypeId << mockAsyncFailingActionTypeId << mockFailingActionTypeId << mockWithoutParamsActionTypeId << mockPowerActionTypeId << mockWithoutParamsActionTypeId << mockBatteryLevelActionTypeId << mockSignalStrengthActionTypeId); + << (QList() << mockAsyncActionTypeId << mockAsyncFailingActionTypeId << mockFailingActionTypeId << mockWithoutParamsActionTypeId << mockPowerActionTypeId << mockWithoutParamsActionTypeId << mockBatteryLevelActionTypeId << mockSignalStrengthActionTypeId << mockUpdateStatusActionTypeId << mockPerformUpdateActionTypeId); QTest::newRow("invalid thingClass") << ThingClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << QList(); } @@ -926,7 +926,7 @@ void TestIntegrations::getEventTypes_data() QTest::addColumn("thingClassId"); QTest::addColumn("resultCount"); - QTest::newRow("valid thingClass") << mockThingClassId << 10; + QTest::newRow("valid thingClass") << mockThingClassId << 13; QTest::newRow("invalid thingClass") << ThingClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0; } @@ -951,7 +951,7 @@ void TestIntegrations::getStateTypes_data() QTest::addColumn("thingClassId"); QTest::addColumn("resultCount"); - QTest::newRow("valid thingClass") << mockThingClassId << 8; + QTest::newRow("valid thingClass") << mockThingClassId << 11; QTest::newRow("invalid thingClass") << ThingClassId("094f8024-5caa-48c1-ab6a-de486a92088f") << 0; } @@ -1021,7 +1021,7 @@ void TestIntegrations::getStateValues() QCOMPARE(response.toMap().value("params").toMap().value("thingError").toString(), enumValueName(statusCode)); if (statusCode == Thing::ThingErrorNoError) { QVariantList values = response.toMap().value("params").toMap().value("values").toList(); - QCOMPARE(values.count(), 8); // Mock has 8 states... + QCOMPARE(values.count(), 11); // Mock has 11 states... } }