Create a button widget
Weather forecast plugin (part 1)
In this example, you'll learn step-by-step how to develop a widget button by the creation of a plugin which retreives the weather forecast.
Note that this example is the part 1 of a complet plugin in three parts which ultimately displays the weather forecast in a window.
The first part deals with adding a widget button to the interface.
- Step 1: Creating a plugin
- Step 2: Adding a widget button
Warning
This plugin is part of the A.V.A.T.A.R. plugin library.
If you've already installed it, please remove it or save it before continuing !!
Create the plugin
- Start the server in a terminal
-
Create the plugin with Plugin Studio
- Nom :
weather
- Affiché:
Weather forecast
-
Rules: No
-
Script methods:
Language localization methods
Methods for creating and managing widget buttons (onClose() and init() methods are added automatically)
-
Add an image
- Select image
<A.V.A.T.A.R>/resources/app/assets/images/PluginCreation/weather.png
- Select image
-
No documentation
- Nom :
Plugin modification
The Plugin Studio automatically creates a complete application core with files and methods that may be required depending on the type of button and the complexity of the plugin.
The weather plugin is a simple plugin that doesn't require specific methods to update information, so first, we will do a bit of clean-up.
-
Delete the lib folder and its contents.
- Open a terminal and navigate to the plugin folder
cd <A.V.A..T.A.R>/resources/app/cores/plugin/weather
- Delete the lib folder
Note
The lib directory is automatically created with a js file including methods for getting, modifying and setting information of home automation devices in order to create button widgets of
list of values
orfloat
types.The
list of values
andfloat
types are automatically created in Widget Studio according to the type of home automation device.The
Button
type is the only possible type that can be initialized in a plugin.In our example, we create a
Buttons
type to execute an action, the lib directory is not needed. - Open a terminal and navigate to the plugin folder
-
Edit the plugin script file in Visual Studio (or another text editor)
- Open the
<A.V.A.T.A.R>/resources/app/core/plugins/weather/weather.js
file - The plugin has no voice rules, we will take this opportunity to move the getpak() method from the action() method to the init() method.
- Warning: Change data.language to Config.language, the language code is now linked to the application and not to a client language
- Delete all comments and unnecessary imports added during plugin creation (you can keep the comments you like)
The result should look like this:weather.jsimport * as path from 'node:path'; import * as url from 'url'; const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); // Internal module, mandatory to manage widgets import * as widgetLib from '../../../widgetLibrairy.js'; const Widget = await widgetLib.init(); // devices table let periphInfo = []; //language pak let Locale; const widgetFolder = path.resolve(__dirname, 'assets/widget'); const widgetImgFolder = path.resolve(__dirname, 'assets/images/widget'); export async function onClose (widgets) { // Save widget positions if (Config.modules.weather.widget.display === true) { await Widget.initVar(widgetFolder, widgetImgFolder, null, Config.modules.weather); if (widgets) await Widget.saveWidgets(widgets); } } export async function init () { if (!await Avatar.lang.addPluginPak("weather")) { return error('weather: unable to load language pak files'); } Locale = await Avatar.lang.getPak("weather", Config.language); if (!Locale) { return error (`weather: Unable to find '${Config.language}' language pak.`); } } export async function getWidgetsOnLoad () { if (Config.modules.weather.widget.display === true) { await Widget.initVar(widgetFolder, widgetImgFolder, null, Config.modules.weather); let widgets = await Widget.getWidgets(); return {plugin: "weather", widgets: widgets, Config: Config.modules.weather}; } } export async function readyToShow () { } export async function getNewButtonState (arg) { return; } export async function getPeriphInfo () { return periphInfo; } export async function widgetAction (even) { infoConsole(even.value); } export async function action(data, callback) { callback(); }
- Open the
-
Restart A.V.A.T.A.R
- Press Ctrl +
C
in the terminal to stop the server - Get the last command
npm start .
to restart the server
- Press Ctrl +
-
Test the plugin
- No errors should appear in the terminal or in the A.V.A.T.A.R. console
Add a widget button
Initialization
The 1st step is to initialize the button by adding a Button
widget to the periphInfo variable.
Below is a description of the possible keys to a Button
widget:
Key | Format | Mandatory | Description |
---|---|---|---|
name | string | yes | Widget name |
value_type | string | yes | Bouton type. Must always be Button |
usage_name | string | yes | The name of a directory in <plugin>/assets/images/widget where image files for widget states will be used |
periph_id | string | yes | A random value. This value must be unique for all widgets (including other plugins). |
notes | string | no | A widget information note |
-
Add the following lines to the init() method
weather.jsexport async function init () { if (!await Avatar.lang.addPluginPak("weather")) { return error('weather: unable to load language pak files'); } Locale = await Avatar.lang.getPak("weather", Config.language); if (!Locale) { return error(`weather: Unable to find the '${Config.language}' language pak.`); } periphInfo.push({ Buttons: [ { name: "Weather", value_type: "button", usage_name: "Button", periph_id: "808221", notes: "Open weather forecast" } ] }); }
-
Add a currentwidgetState global variable to save the button's current state
weather.js// devices table let periphInfo = []; //language pak let Locale; // button state let currentwidgetState; const widgetFolder = path.resolve(__dirname, 'assets/widget');
-
Add calls to currentwidgetState like in the 2 methods below
weather.jsexport async function getNewButtonState (arg) { return currentwidgetState === true ? "Off" : "On"; } export async function getPeriphInfo () { return periphInfo; } export async function widgetAction (even) { currentwidgetState = even.value.action === 'On' ? true : false; infoConsole(even.value); }
-
Restart A.V.A.T.A.R and get the last command
npm start .
to restart the server
Settings
Once the widget has been initialized, it needs to be configured to appear in the A.V.A.T.A.R. interface.
- Open Widget Studio
- Click on Plugins tab and click on
Weather forecast
plugin -
Scroll down Buttons and click on Weather
-
Action On
:- Select
Weather forecast
plugin - Add an Off parameter
- Select
-
Action Off
:- Select
Weather forecast
plugin - Add an On parameter
- Select
-
Click on the Images tab
- Click on the image On
- Select image
<A.V.A.T.A.R>/resources/app/assets/images/PluginCreation/weather.png
- Select Customized for the device
- Select image
-
Click on the image Off
- Select image
<A.V.A.T.A.R>/resources/app/assets/images/PluginCreation/weather-icon.png
- Select Customized for the device
- Select image
-
Click on the Create button
- The button appears in the A.V.A.T.A.R. interface
- You can test it by clicking on it
- Click on the Settings tab
- Set the Opacity slider to 0
- Click on the Modify button
- The button's border is now transparent in the A.V.A.T.A.R. interface
- Click on close to exit the Widget Studio window
- In the A.V.A.T.A.R interface, move the button by selecting its (transparent) border
-
To save its location, exit A.V.A.T.A.R via the node server menu.
Warning
Do not Ctrl +
C
in the terminal, otherwise the Onclose() method will not be executed and the location will not be saved. -
In the terminal, retrieve the last command
npm start .
to restart the server.
Success
We now have a Weather button in the A.V.A.T.A.R. interface!
Add button actions
The widgetAction method executes a infoConsole, you can check the actions On
and Off
by opening A.V.A.T.A.R's Chromium console.
export async function widgetAction (even) {
currentwidgetState = even.value.action === 'On' ? true : false;
infoConsole(even.value);
// Returns:
// {
// action: "On"
// description: "Off"
// plugin: "Weather forecast"
// }
}
In the following example, we will display the weather forecast in a window.