Skip to content

Create a plugin

The application allows you to create a plugin automatically via Plugin Studio. Although this is not essential for advanced users, we strongly advise you to always use it to have file templates directly in the right format and including the methods and properties useful for your development.

In addition to the server, plugins can be added to each A.V.A.T.A.R client.
A client plugin is generally used to perform client-specific actions that cannot be performed with APIs from a server plugin, or to add button wigdets to the client interface.

Note

it is not possible to create a plugin in a client's Plugin Studio.

To create a plugin for a client :

  1. Create the plugin via the server's Plugin Studio.
  2. Then copy the plugin to the client plugins folder.
  1. In the server interface, left-click on the server node.
  2. Menu Edit -> Plugin Studio.
  3. Left-click to open the Plugin tab.
  4. Click on Create a Plugin to open the plugin creation window.

Step 1 - General information

  • Enter a name (required): For the exercise, enter myFirstPlugin
  • Enter a display label (optional): For the exercise, enter my first plugin

Screenshot

  • Click on Next

Step 2 - The intention

The intention allows to check whether the sentence you are speaking validates a voice rule defined for the plugin.

  • The plugin has voice rules?
    • Voice rules are not mandatory for a plugin.
      For example, a plugin can manage automations or actions on peripherals directly without voice rules.
    • For the exercise, choose Yes.
  • How are plugin rules checked?
    • There are two ways to check a speech rule:
      • By the syntax of the sentence.
      • By a term in the sentence.
    • For the exercise, choose By sentence syntax.
Note

These choices are explained in detail in the intention section.

Screenshot

  • Click on Next

Step 3 - The script

The script is the entry point for developing a plugin.
This step allows you to automatically add methods that interact with the application when necessary.

Screenshot

  • For the exercise, choose:

    • init() method
    • Language localization methods
    • cron() method
  • Click on Next

Step 4 - Image and documentation

  • Image - Choose an image in png format to be displayed for the plugin. An image is added by default if no image is selected.
  • Documentation - The Information tab in Plugin Studio is available for displaying information about the plugin. In some cases, it may be preferable to create html documentation accessible via a browser. If the documentation requires an HTTP server, the A.V.A.T.A.R server can be used as the documentation server.
Note

To access a plugin's documentation, open the plugins tab, then do a left-click on the plugin. If the plugin is not the current one, the tab will close, so try again to display its contextual menu. If the plugin has documentation, the Documentation menu will appear.

Screenshot

  • Click on select then move to the assets/images/pluginCreation folder.
  • Select the myFirstPlugin image.
    • This image is an example; you can choose any png image from any directory. The image will be copied and renamed in the plugin's images folder.
  • Click on yes for HTML documentation.
    • Add a index.html start page.
    • Click on the “Documentation server” checkbox.
  • click on Next.

Step 5 - Summary

Screenshot

  • Review the creation information, then click on Create

Step 6 - Creation

  • The myFirstPlugin plugin information page is displayed.
  • Open the Plugins tab, My first plugin has been added.

Screenshot

  • Click on the Properties tab to view the plugin's properties.

Screenshot

  • Click on the plugin to open its menu and click on documentation.

Screenshot

  • Close Plugin Studio.

Files created

Several files have been automatically created for the plugin, depending on the choices made earlier in the <A.V.A.T.A.R>/resources/app/core/plugins/myFirstPlugin folder.

Details of the files created for the myFirstPlugin project:

The intention file for checking whether the phrase you're speaking corresponds to a speech rule defined for the plugin.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import {default as _helpers} from '../../ia/node_modules/ava-ia/helpers/index.js';

export default async function (state, actions) {
    if (state.isIntent) return (0, _helpers.resolve)(state);

    for (var rule in Config.modules.myFirstPlugin.rules) {   
        var match = (0, _helpers.syntax)(state.sentence, Config.modules.myFirstPlugin.rules[rule]);     
        if (match) break;
    }

    if (match) {
        state.isIntent = true;
        state.rule = rule;
        return (0, _helpers.factoryActions)(state, actions);
    } else 
        return (0, _helpers.resolve)(state); 
};

The action file called if the sentence is validated.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import {default as _helpers} from '../../ia/node_modules/ava-ia/helpers/index.js'

export default function (state) {
    return new Promise((resolve) => {
        setTimeout(() => { 
            state.action = {
                module: 'myFirstPlugin',
                command: state.rule
            };
            resolve(state);
        }, Config.waitAction.time);
    });
};

The script file called by the action file.

The script file including:

  • Line 7: The init() method executed when the plugin is loaded.

  • Line 8: Loads pack of the localized messages.

  • Line 13: The cron() function for executing tasks at regular intervals.

  • Line 17: The action() function is the entry point for all plugin actions.

  • Line 20: Searchs for localized messages for the client language.

  • Ligne 45: The test() function is the generic private test function added when the plugin was created. It must then be deleted.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import * as path from 'node:path';
import * as url from 'url';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));

let Locale;

export async function init() {
    if (!await Avatar.lang.addPluginPak("myFirstPlugin")) {
        return error('myFirstPlugin: unable to load language pak files');
    }   
}

export async function cron () {
    // Do stuff
}

export async function action(data, callback) {

    try {
        Locale = await Avatar.lang.getPak("myFirstPlugin", data.language);
        if (!Locale) {
            throw new Error (`myFirstPlugin: Unable to find the '${data.language}' language pak.`);
        }

        // Table of actions
        const tblActions = {
            // test (see rules table in the property file)
            test : () => test(data.client)                  
        }

        // Writes info console
        info("myFirstPlugin:", data.action.command, L.get("plugin.from"), data.client);

        // Calls the function that should be run
        tblActions[data.action.command]();
    } catch (err) {
        if (data.client) Avatar.Speech.end(data.client);
        if (err.message) error(err.message);
    }   

    callback();

}

const test = (client) => {

    Avatar.speak(Locale.get(["message.test", client]), client);

}   

The plugin properties file including:

  • Ligne 3: A required modules.myFirstPlugin object containing all plugin properties.

  • Ligne 6: A modules.myFirstPlugin.rules object with which the intention is checked in the intent.myFirstPlugin.js file.

  • Ligne 11: A cron object as requested when creating the myFirstPlugin plugin and defining the execution interval of the cron() function in the myFirstPlugin.js file. Default is every 2 hours.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
    "modules": { 
        "myFirstPlugin": {
            "version": "1.0",
            "name": "My first plugin",
            "rules": {
                "test": ["test * (command|order)"]
            }
        }
    },
    "cron": {
        "myFirstPlugin": { 
            "name": "myFirstPlugin",
            "time": "0 * */2 * * *"
        }
    }
}

The package.json file is not mandatory, the plugin can work just fine without it.
However, this configuration file is preferable if you are adding npm modules to the plugin.

Modify section values as required.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "name": "myFirstPlugin",
    "version": "1.0.0",
    "type": "module",
    "description": "Plugin myFirstPlugin for A.V.A.T.A.R",
    "repository": "https://github.com/YOUR-REPOSITORY",
    "keywords": [
        "myFirstPlugin"
    ],
    "author": "YOUR-NAME",
    "license": "mit"
}

This file has been created as an example and needs to be completed. It contains main objects (here “message”) grouping by category the messages you wish to add in <key>:<value>

Use the function Locale.get(“message.first”) to retrieve the value

1
2
3
4
5
{
    "message": {
        "first":"i am testing the command for $$"
    }
}

The documentation start page defined in the documentation.ini file. This file has been created as an example and must be modified.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">
    </head>
    <body>
        <h1>myFirstPlugin documentation</h1>
    </body>
</html>

Test the plugin

A.V.A.T.A.R is updated with the new plugin without needing to restart.
You can view the plugin loading in the console if show all information option is active.

Say the rule to test the plugin:

  • Rule: test the command



PrerequisitesFolders and files