This is a nice example for showing the very basic concept of the nymea plugin mechanism.
Lets say we want to create a Button device, called Simple button
, which has a press
Action and emits an Event called pressed
when someone executes the press
Action.
Based on this Event we can create a rule and we have a virtual button which can be connected to any Action available in the entire system.
Assuming you have read The plugin wizard tutorial and you have installed all build dependencies we start to create a new plugin project.
In this image sequence you can see how this example was created.
In order to start with the development, you have to take a closer look at the devicepluginsimplebutton.json
file. In this file you can update the definitions of the DevicePlugin, Vendor and DeviceClass.
The full documentation of this plugin definition file and the properties can be found in The plugin JSON File documentation.
{ "name": "SimpleButton", "displayName": "Simple button", "id": "28c7b102-3ac8-41f6-8dc0-f4787222a186", "vendors": [ { "name": "guh", "displayName": "nymea", "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6", "deviceClasses": [ { "name": "simplebutton", "displayName": "Simple button", "id": "c16ba02d-c982-4b45-8ca2-1945d94d8e66", "deviceIcon": "None", "setupMethod": "JustAdd", "createMethods": ["User"], "interfaces": [ "simplebutton" ], "basicTags": [ ], "paramTypes": [ ], "stateTypes":[ ], "actionTypes":[ { "id": "64c4ced5-9a1a-4858-81dd-1b5c94dba495", "name": "press", "displayName": "press" } ], "eventTypes":[ { "id": "f9652210-9aed-4f38-8c19-2fd54f703fbe", "name": "pressed", "displayName": "button pressed" } ] } ] } ] }
First you have to update the plugin, vendor and device class id in the id fields. The wizard initializes these uuids with the default zero uuid. You can use the uuidgen
command to create a new uuid and copy paste it into the id section.
Note: You have to rebuild the whole plugin once you update the deviceplugin JSON file.
As you can see in this example, the plugin name is called SimpleButton
, and will be displayed as Simple button
plugin in the client applications. The name can also be translated. The name will be used to define the debug category for your plugin. In this example the debug categorie will be defined as dcSimpleButton
and can be used like following:
qCDebug(dcSimpleButton()) << "This is a debug information."; qCWarning(dcSimpleButton()) << "This is a debug warning."; qCCritical(dcSimpleButton()) << "This is a critical debug warning.";
The resulting debug output will look like following if the category is enabled:
$ nymead -n -d SimpleButton ... I | SimpleButton: This is a debug information. W | SimpleButton: This is a debug warning. C | SimpleButton: This is a critical debug warning.
This makes it easy to enable / disable the debug output of your plugin.
The Vendor section has not changed, since this example was developed from the guh Vendor.
In order to give this simple button the required action and event described in the beginning of this tutorial, we have to define the appropriate types:
"actionTypes":[ { "id": "64c4ced5-9a1a-4858-81dd-1b5c94dba495", "name": "press", "displayName": "press" } ],
This is the most simple action you can create. The name
property definies how the action will be called in the system. The displayName
definies the string how the action will be displayed to the user and in the client applications.
"eventTypes":[ { "id": "f9652210-9aed-4f38-8c19-2fd54f703fbe", "name": "pressed", "displayName": "button pressed" } ]
This is the most simple event you can create. The name
property definies how the event will be called in the system. The displayName
definies the string how the event will be displayed to the user and in the client applications.
As you may have noticed, this example represents already an interface. The simplebutton interface offers a template for general simple buttons which are able to emit a pressed
event. In order to make use of the interface you simply add the interface to the list.
... "interfaces": [ "simplebutton" ], ...
The server will verify if the required types for an interface match the template. This will be evaluated once the server loads the plugin.
Once you updated the JSON file, you have to rebuild the whole plugin in order to trigger a rebuild of the the plugin information include files.
Before the source code will be compiled, a precompiler called nymea-generateplugininfo
will be launched. This tool will read the plugin JSON file and generate two header files for the plugin in the build directory.
As you can see here this file contains all uuid definitions and translation string generated from the plugin JSON file. This file will regenerated every time you
/* This file is generated by the nymea build system. Any changes to this file will * be lost. * * If you want to change this file, edit the plugin's json file. */ #ifndef PLUGININFO_H #define PLUGININFO_H #include <QLoggingCategory> #include <QObject> #include "typeutils.h" // Id definitions PluginId pluginId = PluginId("28c7b102-3ac8-41f6-8dc0-f4787222a186"); VendorId guhVendorId = VendorId("2062d64d-3232-433c-88bc-0d33c0ba2ba6"); DeviceClassId simplebuttonDeviceClassId = DeviceClassId("c16ba02d-c982-4b45-8ca2-1945d94d8e66"); ActionTypeId simplebuttonPressActionTypeId = ActionTypeId("64c4ced5-9a1a-4858-81dd-1b5c94dba495"); EventTypeId simplebuttonPressedEventTypeId = EventTypeId("f9652210-9aed-4f38-8c19-2fd54f703fbe"); // Logging category Q_DECLARE_LOGGING_CATEGORY(dcSimpleButton) Q_LOGGING_CATEGORY(dcSimpleButton, "SimpleButton") // Translation strings const QString translations[] { //: The name of the plugin SimpleButton (28c7b102-3ac8-41f6-8dc0-f4787222a186) QT_TRANSLATE_NOOP("SimpleButton", "Simple button"), //: The name of the vendor (2062d64d-3232-433c-88bc-0d33c0ba2ba6) QT_TRANSLATE_NOOP("SimpleButton", "nymea"), //: The name of the DeviceClass (c16ba02d-c982-4b45-8ca2-1945d94d8e66) QT_TRANSLATE_NOOP("SimpleButton", "Simple button"), //: The name of the ActionType 64c4ced5-9a1a-4858-81dd-1b5c94dba495 of deviceClass simplebutton QT_TRANSLATE_NOOP("SimpleButton", "press"), //: The name of the EventType f9652210-9aed-4f38-8c19-2fd54f703fbe of deviceClass simplebutton QT_TRANSLATE_NOOP("SimpleButton", "button pressed") }; #endif // PLUGININFO_H
/* This file is generated by the nymea build system. Any changes to this file will * be lost. * * If you want to change this file, edit the plugin's json file. */ #ifndef EXTERNPLUGININFO_H #define EXTERNPLUGININFO_H #include "typeutils.h" #include <QLoggingCategory> // Id definitions extern PluginId pluginId; extern VendorId guhVendorId; extern DeviceClassId simplebuttonDeviceClassId; extern ActionTypeId simplebuttonPressActionTypeId; extern EventTypeId simplebuttonPressedEventTypeId; // Logging category definition Q_DECLARE_LOGGING_CATEGORY(dcSimpleButton) #endif // EXTERNPLUGININFO_H
In order to implement this simple action and emit the Event once the button will be pressed, you need to implement following code:
DeviceManager::DeviceError DevicePluginSimpleButton::executeAction(Device *device, const Action &action) { qCDebug(dcSimpleButton()) << "Executing action for device" << device->name() << action.actionTypeId().toString() << action.params(); // Check the device class if (device->deviceClassId() == simplebuttonDeviceClassId) { // Check the action type if (action.actionTypeId() == simplebuttonPressActionTypeId) { // Emit the pressed event on button press qCDebug(dcSimpleButton()) << "Emit event pressed for simple button" << device->name(); emitEvent(Event(simplebuttonPressedEventTypeId, device->id())); return DeviceManager::DeviceErrorNoError; } // Unhandled action type return DeviceManager::DeviceErrorActionTypeNotFound; } // Unhandled device type return DeviceManager::DeviceErrorDeviceClassNotFound; }
In this code section you can see the implementation of the executeAction
method for this example tutorial. The method will be called from DeviceManager once an Action should be executed. First we have to check for which device class this action is ment. The we have to check which action of this device class should be executed. In this example we have only one deviceclass and one action.
emitEvent(Event(simplebuttonPressedEventTypeId, device->id()));
And finally, once the action press
gets called, the event pressed
will be emitted in the system.
This event can be connected whithin a rule to execute whatever action you want.
Now it's time to build you first plugin. In order to make sure all changes in you JSON file are up to date press the Rebuild all
instead of only Build
. This will rerun the nymea-generateplugininfo tool and update the plugininfo.h
and extern-plugininfo.h
files.
Note: Comming soon!
Files: