Skip to main content
Virtual parameters are user-defined parameters whose values are generated by a custom JavaScript script. They behave like regular parameters and appear in the device data model under the VirtualParameters. path. Virtual parameter names cannot contain a period (.). The execution environment for virtual parameter scripts is almost identical to that of provisions — the same built-in functions (declare, clear, commit, ext, log) are available.
Like a regular parameter, creating a virtual parameter does not automatically add it to the parameter list for a device. It must be fetched (manually or via a preset) before it appears in the device data model.

Differences from provisions

Virtual parameter scripts differ from provision scripts in two ways: 1. The args variable has a different structure. Instead of holding preset arguments, args contains the declared and current timestamps and values for the parameter itself:
// [<declared attr timestamps, declared attr values>, <current attr timestamps>, <current attr values>]
[{path: 1559849387191, value: 1559849387191}, {value: ["new val", "xsd:string"]}, {path: 1559840000000, value: 1559840000000}, {value: ["cur val", "xsd:string"]}]
  • args[0] — declared attribute timestamps
  • args[1] — declared attribute values (what the caller wants to set)
  • args[2] — current attribute timestamps
  • args[3] — current attribute values
2. The script must return a value. Virtual parameter scripts must return an object containing the attributes of the parameter, at minimum writable and value:
return {writable: false, value: ["some value", "xsd:string"]};
You cannot pass custom arguments to a virtual parameter script.

Examples

This virtual parameter exposes a single MACAddress regardless of whether the device uses the Device.* or InternetGatewayDevice.* data model.
// Example: Unified MAC parameter across different device models
let m = "00:00:00:00:00:00";
let d = declare("Device.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.MACAddress", {value: Date.now()});
let igd = declare("InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANPPPConnection.*.MACAddress", {value: Date.now()});

if (d.size) {
  for (let p of d) {
    if (p.value[0]) {
      m = p.value[0];
      break;
    }
  }  
}
else if (igd.size) {
  for (let p of igd) {
    if (p.value[0]) {
      m = p.value[0];
      break;
    }
  }  
}

return {writable: false, value: [m, "xsd:string"]};
This virtual parameter reads from and writes to an external data store via an extension script. When a new value is declared, it is persisted externally and returned; otherwise the current external value is fetched and returned.
// Example: Expose an external value as a virtual parameter
let serial = declare("DeviceID.SerialNumber", {value: 1});
if (args[1].value) {
  ext("example-ext", "set", serial.value[0], args[1].value[0]);
  return {writable: true, value: [args[1].value[0], "xsd:string"]};
}
else {
  let v = ext("example-ext", "get", serial.value[0]);
  return {writable: true, value: [v, "xsd:string"]};
}
This virtual parameter provides a single writable interface for the WPA passphrase, abstracting over both the Device.* and InternetGatewayDevice.* data model paths.
// Example: Create an editable virtual parameter for WPA passphrase
let m = "";
if (args[1].value) {
  m = args[1].value[0];
  declare("Device.WiFi.AccessPoint.1.Security.KeyPassphrase", null, {value: m});
  declare("InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.KeyPassphrase", null, {value: m});
}
else {
  let d = declare("Device.WiFi.AccessPoint.1.Security.KeyPassphrase", {value: Date.now()});
  let igd = declare("InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.KeyPassphrase", {value: Date.now()});

  if (d.size) {
    m = d.value[0];
  }
  else if (igd.size) {
    m = igd.value[0];  
  }
}

return {writable: true, value: [m, "xsd:string"]};