• Getting Started
  • Getting Started

    Video for this tutorial

    Plugins in nymea are used to exand the functionalitys and capabilitys of the nymea server. A plugin is basically a shared library, which will be loaded dynamically from the nymea server during the start up process. Each plugin has a name, a uuid and a list of supported vendors which will be visible in the system once the plugin is loaded. Each of thouse Vendors contains a list of supported DeviceClasses. A DeviceClass describes how the supported Device looks like, how it will be created (CreateMethod), how the setup (SetupMethod) looks like and what you can do with the Device.

    Devices

    A device in nymea can represent a real device, a gateway or even a service like weather. When you want to represent you own device / service in nymea, you should try to abstract that device and think in terms like:

    • ParamTypes → A Device can have Params, which will be needed to set up the device (like IP addresses or device configurations) and give information for the user like name or location. The ParamType represents the description of an actual Param.
    • StateTypes → A Device can have States, which basically represent a value of a Device like current temperature or ON/OFF. The StateType represents the description of an actual State.
    • EventTypes → A Device can emit Events, which basically represent a signal. An example of an Event could be: Button pressed. An Event can have Params to give the possibility to pass information with the signal. The EventType represents the description of an actual Event.
    • ActionTypes → A Device can execute Actions, which represent basically a method for the Device which the user can execute. An example of an Action could be: Set temperature. An Action can have Params to give the possibility to parameterize the action. The ActionType represents the description of an actual Action.

    The DeviceClass represents the description of an actual Device.

    Hardware resources

    The libnymea provides a list of HardwareResources, which can be used in every plugin. When sou start writing a plugin, you need to know which resource you will need. Each resource provides it's own interface for a DevicePlugin. In the plugin you don't have to take care about the resource.

    Getting started with a plugin

    In order to show how a plugin ist structured here is an example of the most minimalistic device plugin possible for the nymea system.

    For an easier start we provide a set of plugin templates which can be used for your own plugin and to have a basic for the tutorials described in this documentation. You can get the templates with following command:

    $ git clone https://github.com/guh/plugin-templates.git

    This will create the plugin-templates folder containing all templates and examples you will need to write your own plugin. Let's start with the smallest, simplest plugin.

    Basic structure

    The name of the plugin should be clear and inform about the content in one word. In this first minimalistic example the <pluginName> is "minimal".

    The basic structure of the minimal plugin looks like this:

        $ cd plugin-templates
        $ ls -l minimal/
    
        devicepluginminimal.cpp
        devicepluginminimal.h
        devicepluginminimal.json
        minimal.pro
        plugins.pri

    minimal.pro

    The minimal.pro file is the project file of the plugin, which can be openend with the Qt Creator. The name of this file should be the same as the folder name of the project. In this example the name would be "minimal".

    include(plugins.pri)
    
    TARGET = $$qtLibraryTarget(nymea_devicepluginminimal)
    
    message("Building $$deviceplugin$${TARGET}.so")
    
    SOURCES += \
        devicepluginminimal.cpp \
    
    HEADERS += \
        devicepluginminimal.h \

    The TARGET parameter definens the name of the resulting plugin lib file and should should have following name structure:

    nymea_deviceplugin<pluginName>

    In this example the pluginname is minimal, which means the lib file name will be nymea_devicepluginminimal.so. You can check the name of the plugin in the "Project Messages" (alt + 6 in Qt Creator).

    The SOURCES and HEADERS variables define the .cpp and .h files of your plugin like in any other Qt project.

    plugins.pri

    The plugins.pri file contains all relevant definitions and configuration to build a plugin. Each plugin must contain this file and should not be changed. In this file the precompiler nymea-generateplugininfo will be called.

        TEMPLATE = lib
        CONFIG += plugin
    
        QT += network
    
        QMAKE_CXXFLAGS += -Werror -std=c++11
        QMAKE_LFLAGS += -std=c++11
    
        INCLUDEPATH += /usr/include/nymea
        LIBS += -lnymea
    
        infofile.output = plugininfo.h
        infofile.commands = /usr/bin/nymea-generateplugininfo ${QMAKE_FILE_NAME} ${QMAKE_FILE_OUT}
        infofile.depends = /usr/bin/nymea-generateplugininfo
        infofile.CONFIG = no_link
        JSONFILES = deviceplugin"$$TARGET".json
        infofile.input = JSONFILES
    
        QMAKE_EXTRA_COMPILERS += infofile
    
        target.path = /usr/lib/nymea/plugins/
        INSTALLS += target

    If you need an extra Qt module i.e. serialport please add it in the <pluginName>.pro file an not in the plugin.pri:

    Note: Please make sure you have installed the corresponding development libs i.e. sudo apt-get install libqt5serialport5-dev

        QT += serialport

    devicepluginminimal.json

    The properties of a plugin will be definend with in the JSON file containing all needed information for nymea to load it. The name convention fot the json file is:

    deviceplugin<pluginName>.json

    This file must have a clear, definend structure and looking like this:

    Note: For more details about the structure, values and objects please take a look at the The Plugin JSON File documentation.

        {
            "name": "Minimal plugin",
            "idName": "Minimal",
            "id": "6878754a-f27d-4007-a4e5-b030b55853f5",
            "vendors": [
                {
                    "name": "Minimal vendor",
                    "idName": "minimal",
                    "id": "3897e82e-7c48-4591-9a2f-0f56c55a96a4",
                    "deviceClasses": [
                        {
                            "deviceClassId": "7014e5f1-5b04-407a-a819-bbebd11fa372",
                            "idName": "minimal",
                            "name": "Minimal device",
                            "createMethods": ["user"],
                            "basicTags": [
                                "Device"
                            ],
                            "paramTypes": [
                                {
                                    "name": "name",
                                    "type": "QString",
                                    "defaultValue": "Minimal device"
                                }
                            ]
                        }
                    ]
                }
            ]
        }

    In this minimal example of a device plugin we have one Vendor ("Minimal vendor") with the VendorId 3897e82e-7c48-4591-9a2f-0f56c55a96a4, which contains one DeviceClass with the name "Minimal device". The DeviceClass has one QString Param called name.

    devicepluginminimal.h

    The main header file of the plugin. The naming convention is:

    deviceplugin<pluginName>.h

    In this file you can find the main class of the plugin: DevicePluginMinimal. As you can see the DevicePluginMinimal inherits from the class DevicePlugin. You can check out the DevicePlugin class description to find how a DevicePlugin looks like.

        #ifndef DEVICEPLUGINMINIMAL_H
        #define DEVICEPLUGINMINIMAL_H
    
        #include "plugin/deviceplugin.h"
        #include "devicemanager.h"
    
        class DevicePluginMinimal : public DevicePlugin
        {
            Q_OBJECT
    
            Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "devicepluginminimal.json")
            Q_INTERFACES(DevicePlugin)
    
        public:
            explicit DevicePluginMinimal();
    
            DeviceManager::HardwareResources requiredHardware() const override;
            DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
        };
    
        #endif // DEVICEPLUGINBOBLIGHT_H

    As you can see this class has two methods which override the corresponding method in the DevicePlugin class. These two methods are pure virtual, which meas you must implement them.

    devicepluginminimal.cpp

    The implementation of the DevicePlugin. The naming convention is:

    deviceplugin<pluginName>.cpp

        #include "devicepluginminimal.h"
        #include "plugininfo.h"
    
        DevicePluginMinimal::DevicePluginMinimal()
        {
        }
    
        DeviceManager::HardwareResources DevicePluginMinimal::requiredHardware() const
        {
            return DeviceManager::HardwareResourceNone;
        }
    
        DeviceManager::DeviceSetupStatus DevicePluginMinimal::setupDevice(Device *device)
        {
            Q_UNUSED(device)
            qCDebug(dcMinimal) << "setup device" << device->name() << device->id();
    
            return DeviceManager::DeviceSetupStatusSuccess;
        }

    Now you can start with Tutorial 1 - The "Minimal" plugin.