Setting a Virtual Parameter value from extension

Hi, im new on using GenieACS. I have been working on a API to get the PPPoE users from GenieACS database and return their respective OLT from our database. It’s done, but, i don’t know if there’s a way to to set a VParam named as “DeviceOLT” for each device, and set its value from a extension.

Does anyone have a clue about it?

You can’t set the value from the extension script (unless you make an API call). But what you can do is have the extension script return the OLT serial/mac/whatever you track and have the provision script that calls the extension script set the vparam.

For now, we return the value in a JSON from a HTTP consult as follows:

[
{
“olt”: “OLT 1 NAME”,
“username”: “123456789b”
},
{
“olt”: “OLT 2 NAME”,
“username”: “123456789b”
}
]

That’s what we have by now, but, i’m wasn’t able to find any related issue. What you think?

I’m not sure what you are asking.

Sorry, i’ll try to explain in a better way.

For now, as a mentioned, we’re trying to set a Virtual Parameter where it’s value would come from a extension. Like you mentioned, it’s not possible unless we make a API Call, but, that’s exactly what we’re doing.

The extension is returning a array with objects, and, each object has 2 attributes, “olt” and “pppusername”.

What i want to know is if there’s a way to travel through this array on “0 BOOTSTRAP” and if InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection equals to any of the usernames from the objects, it would set it’s it’s DeviceOLT value from the same object.

I’ve been trying to do this for a while now, but, sorry if i’m mistaken in any way and thanks to answer me.

Here’s an example of the Extension:

const axios = require("axios");

const apiURL = "https://api.link/enpoint";

function fetchSSiDAndSetOLT(args, callback) {
  axios
    .get(apiURL)
    .then((response) => {
      const data = response.data;

      callback(null, data);
    })
    .catch((error) => {
      callback(error);
    });
}

exports.fetchSSiDAndSetOLT = fetchSSiDAndSetOLT;

And here is the provision script:

const now = Date.now();

// Chame a extensão para obter os dados da API
const data = ext("cpe-olt", "fetchSSiDAndSetOLT");

if (data) {
  const usernameParam = declare("InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection.1.Username", { value: 1 }).value[0];

  const matchingObject = data.find((obj) => obj.username === usernameParam);

  if (matchingObject) {
    declare("VirtualParameters.DeviceOLT", { value: matchingObject.ssid });

    log(`DeviceOLT definido para: ${matchingObject.ssid}`);
  } else {
    declare("VirtualParameters.DeviceOLT", { value: "" });

    log("Nenhuma correspondência encontrada para o username.");
  }
} else {
  log("Não foi possível obter os valores da API.");
}```

What you have should work. What is not working for you?

One thing I would do is use a vparam for the pppoe username. When you get devices that use TR181, or add fiber to your environment the WANDevice instance will change. Heres the vparam code for pppoe username.

let username = '';
const now = Date.now();

if ("value" in args[1]) {
    username = args[1].value[0];
    declare('InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANPPPConnection.*.Username', {path: now, value: now}, {value: username})
    declare('Device.PPP.Interface.*.Username', {path: now, value: now}, {value: username})
} else {
    let keys = [
        'InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANPPPConnection.*.Username',
        'Device.PPP.Interface.*.Username'
    ];

    username = getParameterValue(keys);
}

log('PPPoEUsername: ' + username);
return {writable: true, value: [username, "xsd:string"]};

function getParameterValue(keys) {
    for (let key of keys) {
        let d = declare(key, {path: Date.now() - (120 * 1000), value: Date.now()});

        for (let item of d) {
            if (item.value && item.value[0]) {
                return item.value[0];
            }
        }
    }

    return 'UNKNOWN';
}

Thank you so much for that tip! I’ll consider deploying it too.

For some reason, i keep getting the following message:

No such function ‘fetchSSiDAndSetOLT’ in extension ‘cpe-olt’

That’s exactly how the function is called, and for some reason the VParam isn’t getting set too. Could it be any incompatibility or something like this? We get the log we want to, it just dont set its value.

Again, thank you so much for the reply! Hope you have a good day :slightly_smiling_face:

Fortunately, as soon as I restarted the genie processes in the VM, everything started working normally again, but still not as expected.

I think I misunderstood how provisioning and virtual parameters work. As soon as I placed that script inside Visual Parameter instead of Provisions, VParam was declared as expected, but, with empty values.

The only point left now would be to update it’s value automatically with some event, like 0 BOOTSTRAP or something like that, since I’m having to update the value manually within the device.

Is there any way to update this VParam with a provision?

GenieACS must be restarted if you make changes to extension scripts. This is because the script is cache after first load.

A preset can call one or more provision scripts. A provision script can call one (or more) extension scripts, and can also set params and vparams via declare. Make sense?

There should be a default Bootstrap provision you can hook into. See this wiki entry for an example on how to set things up.

Oh, now i see why i need to restart it everytime lol. Thank you so much!

I got what you said precisely after looking onto the Provisioning Script you linked, but, for some reason, when i set the same script for Provision, he consults the API, get the right return, but, the declare doesn’t set the VParam. When i set the same script on Virtual Parameter tab, it works, but, if i do so, i’ll need to somehow update it’s value on some other Provision Script i guess.

This VParam update would need to be done bt calling its script, not setting an old value again, like the hourly from Default Provisioning. Check it out:

const now = Date.now();
const usernameParam = declare("InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection.1.Username", { value: 1 }).value[0];

const data = ext("cpe-olt", "SetOLT", usernameParam);
if (data.length > 0) {  
   	declare("VirtualParameters.DeviceOLT", { value: data[0].ssid });
    log(`DeviceOLT definido para: ${data[0].ssid}`);

    return {writable: false, value: [data[0].ssid, "xsd:string"]}
} else {  
  log("Unable to get API values.");

  declare("VirtualParameters.DeviceOLT", { value: "" });
  return {writable: false, value: ["", "xsd:string"]}
}

Any thoughts on what could be happening? I’m actually working on GenieACS for 2 weeks by now, so, if i was mistaken on anything i said, it would be a great pleasure if you could give me a hint on how to work things out. :slightly_smiling_face:

PS: I did some updates to optimize the process and set the PPPoE as a Parameter to call the Extension, then, the API would only return it’s OLT, not a enormous array of data.

Is that script your vparam script? IMO, vparams should be pretty simple, and not call out to extension scripts. That work should be done in a provision script which then sets the vparam. All of my vparam scripts are stupid simple and all the logic happens in the provision and I have zero issues.

Yes, it is the script for the vparam, but, like i said, when i set the same script to provisions, it does everything, but, set the vparam correctly, you know?

Let’s assume i put it on a provision script. It’ll get que correct callback and even if i print it on the log, it shows what i want, but, it doesn’t declare the Vparam.

declare("VirtualParameters.DeviceOLT", { value: data[0].ssid });
    log(`DeviceOLT definido para: ${data[0].ssid}`);

    return {writable: false, value: [data[0].ssid, "xsd:string"]}

This declare on Provision doesn’t seem to work, but, if i use THE EXACT SAME SCRIPT on Virtual Param, and refresh it manually (apparently i can’t call vparam on provision to put it on a preset and refresh at any event), works just fine.

Is this from your provision script? Your declare syntax is incorrect. Try this

declare("VirtualParameters.DeviceOLT", null, { value: data[0].ssid });

Uh, thank you soo much!! It works just fine like this. I also tried “inverting” it and also works. Check it out:

image

I just call the Provision “update_DeviceOLT” at any preset and when it reads the VParam, refresh it’s value. Maybe i could also call it on Default, but, i’ll leave it like this. If there’s any bad habit in doing it this way, I would appreciate open-minded recommendations to improve!

Anyway, thank you very much for your help! Hope this topic also helps anyone else with the same problem

A couple of things I see in your vparam script. First, change line 3 to this: const serial = declare('DeviceID.SerialNumber', {value: 1}); Does the serial number ever change on a CPE :smiley:. Yes, DeviceID.SerialNumber is an internal vparam, but its still a good habbit to get into to not refresh data that doesn’t change.

Second, remove lines 7, 12 and 15. They aren’t necessary. 7 and 12 set you up for unnecessary recursion. commit is only needed in extraordinary circumstances.

1 Like