This tutorial shows you how to start a new plugin project using the nymea-qtcreator wizard. You can find the source code of the qt-creator wizard on our github page.
Once you have installed all packages required for development, you can open the Qt Creator and start a new project. If you need help with the overall Qt Creator project creation, you can find more information here.
In the template view cou can find now the nymea section. In that section you can find the template for a new plugin.
Choose the project name and the path where the project should be located. As in this example the name is template and will be used within the source code as refference. A good practice is to pick a general describing name like a vendor or product/project name.
In this section the plugin details can be defined.
In the first part you can find the c++ specific definitions:
DevicePluginName
in camel case.In the second part you can find the json specific definitions:
See also the CreateMethods and SetupMethods section.
Enter the name and email address of the developer for this plugin. These information will be used in the copyright sections of the plugin. The copyright information are placed in the debian/copyright
file and in each source code license header.
Pick the build kit for this project. The kit must match the version of the nymead
and libnymea1
built.
Note: : You have to make sure you are using the same kit as the nymea daemon and libraries use. If you have installed the nymea library and Qt libraries from you default system package manager, you should probably go with the default kit of your distribution.
Here you can select your prefered project management tool. If you choose git, the default .gitignore
file will be added to the project.
Once you finished the plugin wizard, you can start with the development of you plugin.
Starting with the new created project you can find following files in you project:
This is the generated project files of your plugin. If you need additional qt modules or external libraries in your project you can include them normaly using i.e. QT += network
or INCLUDEPATH += /path/to/includes
and LIBS += -lfoo
like in any other Qt project.
include(/usr/include/nymea/plugin.pri) TARGET = $$qtLibraryTarget(nymea_deviceplugintemplate) message(============================================) message("Qt version: $$[QT_VERSION]") message("Building $$deviceplugin$${TARGET}.so") SOURCES += \ deviceplugintemplate.cpp HEADERS += \ deviceplugintemplate.h
include(/usr/include/nymea/plugin.pri)
TARGET = $$qtLibraryTarget(nymea_deviceplugintemplate)
message(============================================) message("Qt version: $$[QT_VERSION]") message("Building $$deviceplugin$${TARGET}.so")
SOURCES
and HEADERS
section shows the included source code files for your project.SOURCES += \ deviceplugintemplate.cpp HEADERS += \ deviceplugintemplate.h
Here you can find the device plugin interface describing the vendors, devices and plugin information. A detailed description of each section can be found in the The plugin JSON File section.
{ "name": "Template", "displayName": "Template", "id": "00000000-0000-0000-0000-000000000000", "vendors": [ { "name": "guh", "displayName": "nymea", "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6", "deviceClasses": [ { "name": "template", "displayName": "Example", "id": "00000000-0000-0000-0000-000000000000", "deviceIcon": "None", "setupMethod": "JustAdd", "createMethods": ["User"], "interfaces": [ ], "basicTags": [ ], "paramTypes": [ ], "stateTypes":[ ], "actionTypes":[ ], "eventTypes":[ ] } ] } ] }
In the first section you can find the plugin specific properties. The id will be set to zero and must be changed with an actual uuid. The zero uuid is creaed by the plugin template in order to indicate that this field has to be updated.
{ "name": "Template", "displayName": "Template", "id": "00000000-0000-0000-0000-000000000000", "vendors": [
In the vendors section you can see the vendor specific properties. There can be multiple vendors defined in one plugin, each with its own device classes. The uuid of the vendor guh is known, and therefore already filled out. You have to update the vendor uuid, name and id with your plugin information.
{ "name": "guh", "displayName": "nymea", "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6", "deviceClasses": [
Here you can see the default created deviceclass, showing you the basic structure of a device class.
{ "name": "template", "displayName": "Example", "id": "00000000-0000-0000-0000-000000000000", "deviceIcon": "None", "setupMethod": "JustAdd", "createMethods": ["User"], "interfaces": [ ], "basicTags": [ ], "paramTypes": [ ], "stateTypes":[ ], "actionTypes":[ ], "eventTypes":[ ] }
The main header file shows you the basic structure of your DevicePlugin template. The header file start with the license header containing the copyright information passed during the wizard.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Developer Name <developer.name@example.com> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
The main class has the name DevicePluginExample
. The device plugin class inherts from the DevicePlugin class and must implement the pure virtual methods in order build correctly.
class DevicePluginExample: public DevicePlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "deviceplugintemplate.json") Q_INTERFACES(DevicePlugin) public: explicit DevicePluginExample(); void init() override; void startMonitoringAutoDevices() override; void postSetupDevice(Device *device) override; void deviceRemoved(Device *device) override; DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; private: private slots: };
The implementation of each method can be found in the corresponding cpp
file.
As you can see, the plugin includes in the cpp file the plugininfo.h
file, which will be generated during build time from the nymea-generateplugininfo
tool. This tool translates the deviceplugintemplate.json into a c++ header file containing all uuid definitions, tranlations strings and the debug catergory definition.
#include "plugininfo.h"
The main entry point of the plugin is the init() method. This method will be called from the DeviceManager once all plugins are loaded and the initialization phase starts for you all plugins. Here you can start creating your objects in initialize whatever you need. This method can be seen like a constructor.
void DevicePluginExample::init() { // Initialize/create objects }
The startMonitoringAutoDevices method will be called from the DeviceManager once all devices are set up and the plugin can start for searching device which appear automatically if your plugin supports such device types.
void DevicePluginExample::startMonitoringAutoDevices() { // Start seaching for devices which can be discovered and added automatically }
The postSetupDevice method will be called from the DeviceManager once the setup of a device has finished successfully. Here is a good point to initialize the states of the device.
void DevicePluginExample::postSetupDevice(Device *device) { qCDebug(dcTemplate()) << "Post setup device" << device->name() << device->params(); // This method will be called once the setup for device is finished }
The deviceRemoved method will be called from the DeviceManager once a device is about to be removed from the system. Here is a good place to clean up everything releated to the device which will be removed.
void DevicePluginExample::deviceRemoved(Device *device) { qCDebug(dcTemplate()) << "Remove device" << device->name() << device->params(); // Clean up all data related to this device }
When the user wants to add a new device from this plugin, the setupDevice() method will be called. Here you can initialize Objects and set up everything you need for your device.
DeviceManager::DeviceSetupStatus DevicePluginExample::setupDevice(Device *device) { qCDebug(dcTemplate()) << "Setup device" << device->name() << device->params(); return DeviceManager::DeviceSetupStatusSuccess; }
When the user wants to execute an Action of a Device from this DevicePlugin, the executeAction method will be called. Here you can perform the actual execution of the custom call for your Device.
DeviceManager::DeviceError DevicePluginExample::executeAction(Device *device, const Action &action) { qCDebug(dcTemplate()) << "Executing action for device" << device->name() << action.actionTypeId().toString() << action.params(); return DeviceManager::DeviceErrorNoError; }
Files: