Hi there,
I want to automatically add or delete user voiceprofiles with a provision script.
I don’t want to delete all and then add everything like in the example of " Creating/deleting object instances" in the docs like:
// Ensure that *all* other instances are deleted
declare("InternetGatewayDevice.X_BROADCOM_COM_IPAddrAccCtrl.X_BROADCOM_COM_IPAddrAccCtrlListCfg.[]", null, {path: 0});
// Add the two entries we care about
declare("InternetGatewayDevice.X_BROADCOM_COM_IPAddrAccCtrl.X_BROADCOM_COM_IPAddrAccCtrlListCfg.[SourceIPAddress:192.168.1.0,SourceNetMask:255.255.255.0]",  {path: now}, {path: 1});
declare("InternetGatewayDevice.X_BROADCOM_COM_IPAddrAccCtrl.X_BROADCOM_COM_IPAddrAccCtrlListCfg.[SourceIPAddress:172.16.12.0,SourceNetMask:255.255.0.0]", {path: now}, {path: 1});
Because it might be some attributes I dont want to change need to stay like they are.
So I want to know how i can add a voiceProfile with a spezific ID, but after deleting an object and adding a new one with the “.*.”-wildcard, genieacs is not using a used ID. The result is, I get a new object with a new ID… this leads to a result like this:
* InternetGatewayDevice.Services.VoiceService.2.VoiceProfile.1.Line.1.SIP.X_AVM-DE_AuthName  
* InternetGatewayDevice.Services.VoiceService.2.VoiceProfile.10.Line.1.SIP.X_AVM-DE_AuthName
But I want the new profile to have the ID “2”, instead it creates an object with the ID “10”…
I don’t understand why is that so? And how can I change this behaviour?
How I want it to be is something like this:
//example data that will be passed to the script
let prov_data = {
    "voip": {
        "vlan": 6,
        "sip_account": [
            {
                "number": "1001",
                "area_code": "7171",
                "sip_user": "1000001",
                "domain": "sip.domain.de",
                "password": "super_secret_1",
                "status": "active",
                "cancelled_on": null
            },
            {
                "number": "1002",
                "area_code": "7171",
                "sip_user": "1000001",
                "domain": "sip.domain.de",
                "password": "super_secret_2",
                "status": "active",
                "cancelled_on": null
            }
        ]
    },
    "router": {
        "product": "FRITZ!Box 7530",
        "cwmp": "00040E-*****",
        "serial_no": "*********",
        "genie_acs_device_id": "00040E-FRITZ%21Box-**********"
    },
    "options": [
        "option_domain_sip_de",
        "option_private",
        "option_ds_priv"
    ],
    "internet": {
        "vlan": 7,
        "connection_mode_identifier": "ds_priv",
        "bandwidth_down": 100000,
        "bandwidth_up": 50000,
        "protocol": "PPPoE",
        "pppoe_username": "20000001",
        "pppoe_password": "super_secret_internet_password"
    }
}
log("----------------------------------");
log("----------------------------------");
let path = "InternetGatewayDevice.Services.VoiceService.2.VoiceProfile."
// Number of Profiles
let device_n_profiles = declare("InternetGatewayDevice.Services.VoiceService.2.VoiceProfileNumberOfEntries", { value: 1 }, null)
let n_diff = prov_data.voip.sip_account.length - device_n_profiles.value[0];
log("");
log(`device_n_profiles = ${device_n_profiles.value[0]}`);
log(`sip_accounts = ${prov_data.voip.sip_account.length}`);
log(`n_diff = ${n_diff}`)
log("");
if (n_diff > 0) {
  // TODO: add profile
  for (let i = device_n_profiles.value[0]; i < prov_data.voip.sip_account.length; i++) {
    declare(path + i, {path: Date.now()}, {path: prov_data.voip.sip_account.length});
  }
} else if (n_diff < 0) {
  // TODO: remove profile
  for (let i = prov_data.voip.sip_account.length; i < device_n_profiles; i++) {
    clear(path + i, Date.now());
  }
}
Next step I want to do is to iterate through the data and update the instances on the device…
something like so:
for (var i = 1; i <= prov_data.voip.sip_account.length; i++) {
    declare(path + [i] + ".Enable:", { path: Date.now() }, { value: "Enable" })
    declare(path + [i] + ".SIP.RegistrarServer:", { path: Date.now() }, { value: prov_data.voip.sip_account[i - 1].domain })
    declare(path + [i] + ".Line.1.SIP.AuthUserName:", { path: Date.now() }, { value: prov_data.voip.sip_account[i - 1].sip_user })
    declare(path + [i] + ".Line.1.SIP.AuthPassword:", { path: Date.now() }, { value: prov_data.voip.sip_account[i - 1].password })
    declare(path + [i] + ".Line.1.SIP.X_AVM-DE_CountryCode:", { path: Date.now() }, { value: "49" })
    declare(path + [i] + ".Line.1.SIP.X_AVM-DE_OKZ:", { path: Date.now() }, { value: prov_data.voip.sip_account[i - 1].area_code })
    declare(path + [i] + ".Line.1.DirectoryNumber:", { path: Date.now() }, { value: prov_data.voip.sip_account[i - 1].number })
    declare(path + [i] + ".RTP.X_AVM-DE_tx_packetsize_in_ms", { path: Date.now() }, { value: "20" })
    declare(path + [i] + ".X_AVM-DE_GUI_ReadOnly", { path: Date.now() }, { value: "true" })
    declare(path + [i] + ".X_AVM-DE_route_always_over_internet", { path: Date.now() }, { value: "false" })
}
This is what I want to do, but it’s not working as expected yet.
Also:
Is this good or bad practice?
Are there solutions to this? (I couldn’t find anything like this anywhere)
How would you guys handle voiceProfiles?
Thanks for help 