bbfdm/docs/json_plugin_v1.md
2021-11-10 13:37:48 +00:00

8.8 KiB

How to extend Datamodel parameters using Json plugins

It is often required to extend datamodel parameters of the device, extending the datamodel parameters using json plugin is the simplest way for the same.

To extend the datamodel using json plugin, its required to be defined it, as it is defined in TR181.json file and then place that json in '/etc/bbfdm/json/' directory of device.

It is often the case, that the supported mapping might not handle all the scenarios, and required some structural changes to fulfill the new requirements, to make these plugins backward compatible with the older mappings some kind of check was required, which is can be solved with having a "version" field in the plugin, which describes the list of supported mappings with that specific version. This can be added as below:

{
	"json_plugin_version": 1,
	"Device.": {
		"type": "object",
		"version": "2.0",
		"protocols": [
			"cwmp",
			"usp"
		],
		"access": false,
		"array": false,
		"RootDataModelVersion": {
			"type": "string",
			"read": true,
			"write": false,
			"version": "2.4",
			"protocols": [
				"cwmp",
				"usp"
			]
		},
		"Boot!": {
			"type": "event",
			"version": "2.12",
			"protocols": [
				"usp"
			],
			"Cause": {
				"type": "string",
				"read": true,
				"write": true,
				"version": "2.12",
				"protocols": [
					"usp"
				],
				"enumerations": [
					"LocalReboot",
					"RemoteReboot",
					"LocalFactoryReset",
					"RemoteFactoryReset"
				]
			}
		},
		"SelfTestDiagnostics()": {
			"type": "command",
			"async": true,
			"version": "2.12",
			"protocols": [
				"usp"
			],
			"output": {
				"Results": {
					"type": "string",
					"read": true,
					"write": true,
					"version": "2.12",
					"protocols": [
						"usp"
					]
				}
			}
		}
	}
}

Note: If the json_plugin_version is omitted in the json then it means, it is having legacy mapping and considered as json_plugin_version 0.

Now, If we consider the datamodel tree of usp, we have

  • Non-leaf components(Objects/Multi-instance objects)
  • Leaf components (Parameters/commands/events)

And on these tree components, we can do:

  • Get
  • Set
  • Add
  • Del
  • Operate/commands

If we skip multi-instance objects for some time, everything else is stand-along entity, I mean, one parameter is having one specific information, so for those parameters information could be fetched from uci/ubus or some external cli command. The TR181.json has all the required the information about the parameters except how to get it from the device. In json plugin, we solve that by introducing a new element in the tree called mapping, which describes how to process the operations on that specific datamodel parameter.

mapping: [
{
	"type":"<uci/uci_sec/ubus/json/cli>",
}
]

If we consider multi-instance objects, they are kind of special because we have group of information, where one group can be visualize as one instance. Also, the parameters of multi-instance objects also shares data with there parents, apart from that, for others as well, we might require some runtime information to get some mappings, for those scenarios, mapping have some special symbol, all start with '@' symbol, some of them only applicable in case of multi-instance object. Overall all these are just for create the convention so that datamodel can easily be extended without getting into hustle of programming. Again, the plugin handler does not have any intelligence of it own and completely driven by the mapping provided by the enduser, so if mapping is in-correct it would give incorrect result or no result in the datamodel.

Special symbols

@index => Current instance number - 1

@index - 1 => Parent instance number - 1

@index - 2 => Grand parent instance number - 1, and likewise

@Name => Section name of parent

@Parent => data passed by parent

@Count => Returns the count of instances

@Value => Replace with the value passed in set command, used for ubus set

How to have different mappings for get/set:

{
  "Device.X_IOPSYS_EU-UserInterface.": {
    "type": "object",
    "protocols": [
      "cwmp",
      "usp"
    ],
    "access": false,
    "array": false,
    "Password": {
      "type": "string",
      "read": true,
      "write": true,
      "protocols": [
        "cwmp",
        "usp"
      ],
      "mapping": [
        {
          "rpc": "get"
        },
        {
          "rpc": "set",
          "type": "uci",
          "uci": {
            "file": "userinterface",
            "section": {
              "name": "global"
            },
            "option": {
              "name": "password_required"
            }
          }
        }
      ]
    },
    "CurrentLanguage": {
      "type": "string",
      "read": true,
      "write": true,
      "protocols": [
        "cwmp",
        "usp"
      ],
      "range": [
        {
          "max": 16
        }
      ],
      "mapping": [
        {
          "rpc": "get",
          "type": "ubus",
          "ubus": {
            "object": "userinterface",
            "method": "dump",
            "args": {},
            "key": "language"
          }
        },
        {
          "rpc": "set",
          "type": "ubus",
          "ubus": {
            "object": "userinterface",
            "method": "set",
            "args": {"language":"@Value"}
          }
        }
      ]
    }
  }
}

How to map for NumberOfEntries parameter:

These are special parameters all with a suffix "NumberOfEntries", which has count of multi-instance object present. With our mapping, a multi-instance object can be added using ubus or uci mappings, so to get the count of the instances a new special symbol introduced @Count.

mapping on ubus

For multi-instance on ubus mapping, it has to point to an array of objects, so for NumberOfEntries, we need to get the size of that array, which is refered here as @Count

{
  "Device.WiFi.X_IOPSYS_EU_RadioNumberOfEntries": {
	"type": "unsignedInt",
    "protocols": [
      "cwmp",
      "usp"
    ],
    "read": true,
    "write": false,
    "mapping": [
    	{
			"type": "ubus",
			"ubus": {
				"object": "wifi",
				"method": "status",
				"args": {},
				"key": "radios.@Count"
			}
		}
	]
  }
}

mapping on uci

For multi-instance object mapped on uci, it has to point a uci section, so for NumberOfEntries it basically has the count of the sections.

{
  "Device.X_IOPSYS_EU_DropbearNumberOfEntries": {
    "type": "unsignedInt",
    "protocols": [
      "cwmp",
      "usp"
    ],
    "read": true,
    "write": false,
    "mapping": [
    	{
			"type": "uci",
			"uci": {
				"file": "dropbear",
				"section": {
					"type": "dropbear"
				},
				"option": {
					"name": "@Count"
				}
			}
		}
    ]
  }
}

How to pass data from parent node to child node

Multi-instance mapping either maps to array of json objects or uci section, so for the instance parameters, needs to extracts the information from the json data or from the uci section. This data sharing relationship can easily be mapped as below:

{
  "Device.X_IOPSYS_EU_Dropbear.{i}.": {
    "type": "object",
    "protocols": [
      "cwmp",
      "usp"
    ],
    "access": true,
    "array": true,
    "mapping": [
    	{
			"type": "uci",
			"uci": {
				"file": "dropbear",
				"section": {
					"type": "dropbear"
				},
				"dmmapfile": "dmmap_dropbear"
			}
		}
	],
    "PasswordAuth": {
      "type": "boolean",
      "protocols": [
        "cwmp",
        "usp"
      ],
      "read": true,
      "write": true,
      "mapping": [
        {
			"data": "@Parent",
			"type": "uci_sec",
			"key": "PasswordAuth"
        }
      ]
    }
  }
}

Ubus example for the same

{
  "Device.WiFi.X_IOPSYS_EU_Radio.{i}.": {
    "type": "object",
    "protocols": [
      "cwmp",
      "usp"
    ],
    "access": false,
    "array": true,
    "mapping": [
    	{
			"type": "ubus",
			"ubus": {
				"object": "wifi",
				"method": "status",
				"args": {},
				"key": "radios"
			}
		}
	],
    "Noise": {
      "type": "int",
      "read": true,
      "write": true,
      "protocols": [
        "cwmp",
        "usp"
      ],
      "mapping": [
        {
			"data": "@Parent",
			"type": "json",
	  		"key": "noise"
        }
      ]
    },
    "Band": {
      "type": "string",
      "read": true,
      "write": true,
      "protocols": [
        "cwmp",
        "usp"
      ],
      "datatype": "string",
      "mapping": [
        {
          "type": "ubus",
          "ubus": {
            "object": "wifi",
            "method": "status",
            "args": {},
            "key": "radios[@index].band"
          }
        }
      ]
    }
  }
}

Feature supported with this mapping

  • Use of json_plugin_version for mapping extensions
  • Use different mappings for get/set
  • Support for NumberOfEntries parameter
  • Data sharing between parent and child node in multi-instance object
  • Use of index number in mapping
  • Support for set in ubus command