Skip to content

How to create a virtual device

Gregory Sitnin edited this page Oct 22, 2013 · 1 revision

Virtual Device (Vdev) is an instance of a VirtualDevice class' descendant which exposes set of metrics and commands (according to it's type/subtype). Virtual devices are the only runtime instances which is controllable and observable throuh the ZAutomation API.

Technically, VDev is a VirtualDevice subclass which concretize, overrides or extends superclass' methods.

Class definition can be stored in a separate .js-file or reside in an index.js of it's module. It doesn't matter. To load external .js-file you should call executeFile() function.

// ...part of the BateryPolling.init()
executeFile(this.moduleBasePath()+"/BatteryPollingDevice.js");

Every AutomationModule has this.moduleBasePath() which returns String which contains module's exact folder name. This is neccessary due to executeFile() is capable of loading any desired .js-file inside of the ZAutomation folder.

Step 1. Define a VirtualDevice subclass

// Important: constructor SHOULD always be successful
BatteryPollingDevice = function (id, controller) {
    // Always call superconstructor first
    BatteryPollingDevice.super_.call(this, id, controller);

    // Define VDevs properties
    this.deviceType = "virtual";
    this.deviceSubType = "batteryPolling";
    this.widgetClass = "BatteryStatusWidget";

    // Setup some additional metrics (many of them is setted up in a base class)
    this.setMetricValue("someMetric", "someValue");
}

inherits(BatteryPollingDevice, VirtualDevice);

Number of VDev properties is mandatory, others is optional.

VDev class SHOULd always fill in the deviceType property and often fill in the deviceSubType property.

If the particular VDev class can be controller by the client-side widget, it SHOULD define widget's class name in the widgetClass property.

Step 2. Override performCommand() method

BatteryPollingDevice.prototype.performCommand = function (command) {
    var handled = true;

    if ("update" === command) {
        for (var id in zway.devices) {
            zway.devices[id].Battery && zway.devices[id].Battery.Get();
        }
    } else {
        handled = false;
    }

    return handled ? true : BatteryPollingDevice.super_.prototype.performCommand.call(this, command);
}

VDev itself mostly needed to handle commands, triggered by the events, system or the API.

In the example above you could see, that this VDev is capable of performing "update" command. But base class can be capable of performing some othe commands, so the last line calls superclass' performCommand() method if the particular command wasn't handled by the VDev itself.

This extensibility provides the possibility to create a VDev class tree. Take a look at ZWaveGate module as an example of such tree.

Step 3. Instantiate and register your VDev by the module

// ...part of the BatteryPolling.init() method
executeFile(this.moduleBasePath()+"/BatteryPollingDevice.js");
this.vdev = new BatteryPollingDevice("BatteryPolling", this.controller);
this.controller.registerDevice(this.vdev);

First line of code is loads and executes apropriate .js-file which provides BatteryPollingDevice class.

Secnd line instantiates this class.

The last line calls controller's registerDevice method to register and VDev instance.

It's that simple =)