Driver implemented in: vsmGadgetServer

Documentation History

This documentation provides information for the implementation of protocol version 1.0.0.0 and above.

1.0First draft.
1.1Added polling support.(driver version 1.0.3.0)
1.2Added support for basic authentification header.(driver version 1.0.4.0)
1.3Added support to send the tree as json.(driver version 1.0.5.0)

Summary

The concept behind the Simple Rest Client is to provide a 3rd party agnostic Rest driver functionality which can be configured to connect to devices providing a simple structured Rest API for control.

Connection

The driver opens a HTTP connection to the remote device.

Supported Features

The driver can be used to address a simple and limited workflow for a REST API.

Currently, the driver does not support the control of dynamically created content on the device.

Supported Commands

HTTP GET, POST, PUT, PATCH, HEAD

HTTP DELETE could be supported, but without any analysis of the response. So no elements will be deleted from the ember+tree.

v1.0.0 does not support any authentification types yet.

Configuration Details

First a definition must be declated and uploaded to each driver instance. The definition format is json. 

| v 1.0.0 two mandatory root objects | restApi: contains the enpoints of the remote device.
emberTree: contains the ember+tree elements and the relation to the restApi |

Examples

Example 1

The following sample contains a possible definition of the AWS Elemental REST API

{
  "restApi": {
    "endpoints": [
      {
        "path": "/api/live_events",
        "methods": {
          "insertImage1": {
            "method": "POST",
            "timeout": 10000,
            "request": {
              "headers": {
                "accept": "*/*"
              },
              "content": {
                "contentType": "application/xml",
                "contentSource": "file",
                "content": "XmlFiles\\insertImage1.xml"
              }
            }
          },
          "disableImage1": {
            "method": "POST",
            "timeout": 10000,
            "request": {
              "headers": {
                "accept": "*/*"
              },
              "content": {
                "contentType": "application/xml",
                "contentSource": "file",
                "content": "XmlFiles\\disableImage1.xml"
              }
            }
          }
        }
      }
    ]
  },
  "emberTree":{
    "identifier": "Inserts",
    "children": [
      {
        "identifier": "enableInsert1",
        "description": "Insert image 1",
        "type": "command",
        "valueChangeTrigger": true,
        "commands": {
          "valueChange": {
            "path": "/api/live_events",
            "method": "insertImage1",
            "resource": "/SomeId/image_inserter"
          }
        }
      },
      {
        "identifier": "disableInsert1",
        "description": "Disable image 1",
        "type": "command",
        "valueChangeTrigger": true,
        "commands": {
          "valueChange": {
            "path": "/api/live_events",
            "method": "disableImage1",
            "resource": "/SomeId/image_inserter"
          }
        }
      }
    ]
  }
}
JS

Syntax Details:

  • restApi: The Rest API json object.
  • restApi.endpoints: Array of all API URNs (Uniform Resource Names) to use.
  • restApi.endpoints.path: The value of the URN = "/api/live_events".
  • restApi.endpoints.methods: All methods to use for this URN as a dictionary, where the key is a unique user defined method name (= "insertImage1") and the value is an json object.
  • restApi.endpoints.methods.insertImage1.method: The HTTP method = "POST".
  • restApi.endpoints.methods.insertImage1.timeout: The optional timeout for this method.
  • restApi.endpoints.methods.insertImage1.request: The request definition as json object. All other replies than HTTP200(OK) to this request are understood as an error.
  • restApi.endpoints.methods.insertImage1.request.headers: The optional HTTP request headers.
  • restApi.endpoints.methods.insertImage1.request.content: The optional HTTP request content to use for this "POST" method.
  • restApi.endpoints.methods.insertImage1.request.content.contentType: The content-type of the data.
  • restApi.endpoints.methods.insertImage1.request.content.contentSource: The source of the request data "file|inline". The user can define if the content is defined within this file or should be read from a different file.
  • restApi.endpoints.methods.insertImage1.request.content.content: The data of this request. "file" defines the data should be read from a file e.g. "D:\\vsm\\vsmGadgetServer.Net\\SimpleRestClient\\MyAPI\\PostSomeData.xml". The file should contain any human readable data. "inline" defines the request data within this file. See next restApi example.

* emberTree: The ember tree json object.

  • emberTree.identifier: An internal identifier = "Inserts". May be used as root node identifier in the future releases.
  • emberTree.children: Array of json object children.
  • emberTree.children.identifier: Defines the Ember+Identifier.String. This values must be unique within this path, which means no other child should use this identifier.
  • emberTree.children.description: Defines the optional Ember+Description.
  • emberTree.children.type: Defines the type of this element. "Node|Command|String|Int|Float|Bool|Enum". If no type is given, a node will be created. All other types generate a parameter. Command can be compared to a trigger parameter.
  • emberTree.children.valueChangeTrigger: Optional flag which will send all related data on value change request.
  • emberTree.children.commands: An json object which contains the currently supported actions. "getDir|valueChange". NOTE: Only top level elements may contain commands definitions!
  • emberTree.children.commands.valueChange: The "setter" reference to a restApi method.
  • emberTree.children.commands.valueChange.path: The reference to URN of the corresponding restApi.endpoints.path.
  • emberTree.children.commands.valueChange.method: The reference to the method name e.g. restApi.endpoints.methods.insertImage1
  • emberTree.children.commands.valueChange.resource: The optional resource to add to the URN.

Example 1 definition file generates the following Ember Tree:

Example 2

The following sample contains a possible RestApi of a json based RestAPI with value changes:

{
  "restApi": {
      "endpoints": [
      {
        "path": "api/v1/channelStatus",
        "methods": {
          "getStatus": {
            "method": "GET",
            "request": {
              "headers": {
                "accept": "*/*",
                "Authorization": "Basic cGJjiI5FwYXjhMjhjYWR3dGU="
              }
            },
            "reply": {
              "parseAction": "fromJson"
            }
          }
        }
      },
      {
        "path": "api/v1/changeChannel",
        "methods": {
          "changeStatus": {
            "method": "POST",
            "timeout": 10000,
            "request": {
              "headers": {
                "accept": "*/*",
                "Authorization": "Basic cGJjiI5FwYXjhMjhjYWR3dGU="
              },
              "content": {
                "contentType": "application/json",
                "contentSource": "inline",
                "content": "{'channelID': '_%channelID%_', 'nextSourceStatus': '_%source%_'}"
              }
            },
            "reply": {
              "parseAction": "fromState"
            }
          }
        }
      }
    ]
  },
  "emberTree": {
    "identifier": "Channels",
    "children": [
      {
        "identifier": "hdChannel1",
        "description": "HD Channel One",
        "polling": 5,
        "commands": {
          "getDir": {
            "path": "api/v1/channelStatus",
            "method": "getStatus",
            "resource": "/ch1"
          },
          "valueChange": {
            "path": "api/v1/changeChannel",
            "method": "changeStatus"
          }
        },
        "children": [
          {
            "identifier": "channelID",
            "type": "string",
            "defaultValue": "ch1"
          },
          {
            "identifier": "source",
            "type": "string",
            "writeable": true,
            "valueChangeTrigger": true
          }
        ]
      },
      {
        "identifier": "uhdChannel",
        "commands": {
          "getDir": {
            "path": "api/v1/channelStatus",
            "method": "getStatus",
            "resource": "/ch2"
          },
          "valueChange": {
            "path": "api/v1/changeChannel",
            "method": "changeStatus"
          }
        },
        "children": [
          {
            "identifier": "channelID",
            "type": "string",
            "defaultValue": "ch2"
          },
          {
            "identifier": "source",
            "type": "string",
            "writeable": true,
            "valueChangeTrigger": true
          },
          {
            "identifier": "notUsed",
            "type": "enum",
            "writeable": true,
            "enumValues": ["Start", "Stop", "Pause"]
          }
        ]
      }
    ]
  }
}
JS

Syntax Details:

  • restApi.endpoints.methods.getStatus.reply.parseAction: The reply definition "fromJson|fromState". Where fromJson tries to parse the reply and matches it to the defined emberTree layout. If a corresponding parameter has been found, the received value would be accepted. fromState applies the values of any writeable values on HTTP200(OK).
  • restApi.endpoints.methods.changeStatus.request.content.content: If contentSource=inline the user can refer to emberTree parameter values e.g. "{'channelID': '_%channelID%_', 'nextSourceStatus': '_%source%_'}". If the content contains encapsulated entries like _%source%_ this value will be replaced by the ember+value of the corresponding source parameter.

* emberTree.children[hdChannel1].identifier: Defines a node with two commands, where getDir is virtually connected to a ember+getDir command and valueChange will be issued when any child element with "valueChangeTrigger":true gets a new value.

  • emberTree.children[hdChannel1].polling: Defines the polling frequency to call the getDir in seconds
  • emberTree.children[hdChannel1].children[channelID].defaultValue: The user can provide some read-only values if there is a use within a rest api method.
  • emberTree.children[hdChannel1].children[source].writeable: The user can provide a writable flag, which may make sense when only one parameter should be used as valueChangeTrigger.
  • emberTree.children[hdChannel1].children[notUsed].enumValues: If "type": "enum" the user can define custom names for prossible indices. In this example "Start" will send a 0, "Stop" will send a 1 and "Pause" a 2 to the device if referenced to a request.

Example 2 definition file generates the following Ember Tree:

Example 3

The following sample contains a possible json payload based RestApi value changes from the tree. The tree needs to reflect the json hierarchy.

{
  "restApi": {
    "endpoints": [
      {
        "path": "v0_1",
        "methods": {
          "getSfp": {
            "method": "GET",
            "timeout": 10000,
            "request": {
              "headers": {
                "accept": "*/*"
              }
            },
            "reply": {
              "parseAction": "fromJson"
            }
          },
          "putSfp": {
            "method": "PUT",
            "timeout": 10000,
            "request": {
              "headers": {
                "accept": "*/*"
              },
              "content": {
                "contentType": "application/json",
                "contentSource": "treeToJson"
              }
            },
            "reply": {
              "parseAction": "fromState"
            }
          }
        }
      }
    ]
  },
  "emberTree": {
    "identifier": "Pam-IP",
    "children": [
      {
        "identifier": "Spf1",
        "type": "node",
        "commands": {
          "getDir": {
            "path": "v0_1",
            "method": "getSfp",
            "resource": "/config/sfp1"
          },
          "valueChange": {
            "path": "v0_1",
            "method": "putSfp",
            "resource": "/config/sfp1"
          }
        },
        "children": [
          {
            "identifier": "sfp",
            "type": "node",
            "children": [
              {
                "identifier": "apply changes",
                "type": "command",
                "valueChangeTrigger": true,
                "writeable": true
              },
              {
                "identifier": "filters",
                "type": "enum",
                "enumValues": [ "IP only", "IP and Port" ],
                "writeable": true
              },
              {
                "identifier": "video",
                "type": "node",
                "children": [
                  {
                    "identifier": "format",
                    "type": "string",
                    "writeable": true
                  },
                  {
                    "identifier": "offset lines",
                    "type": "int",
                    "writeable": true
                  },
                  {
                    "identifier": "sender type",
                    "type": "string",
                    "writeable": true
                  }
                ]
              },
              {
                "identifier": "flows",
                "type": "nodeArray",
                "children": [
                  {
                    "identifier": "flow1",
                    "type": "node",
                    "children": [
                      {
                        "identifier": "enable",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "ip",
                        "type": "string",
                        "writeable": true
                      },
                      {
                        "identifier": "port",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "channels",
                        "type": "int",
                        "writeable": true
                      }
                    ]
                  },
                  {
                    "identifier": "flow2",
                    "type": "node",
                    "children": [
                      {
                        "identifier": "enable",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "ip",
                        "type": "string",
                        "writeable": true
                      },
                      {
                        "identifier": "port",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "channels",
                        "type": "int",
                        "writeable": true
                      }
                    ]
                  },
                  {
                    "identifier": "flow3",
                    "type": "node",
                    "children": [
                      {
                        "identifier": "enable",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "ip",
                        "type": "string",
                        "writeable": true
                      },
                      {
                        "identifier": "port",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "channels",
                        "type": "int",
                        "writeable": true
                      }
                    ]
                  },
                  {
                    "identifier": "flow4",
                    "type": "node",
                    "children": [
                      {
                        "identifier": "enable",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "ip",
                        "type": "string",
                        "writeable": true
                      },
                      {
                        "identifier": "port",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "channels",
                        "type": "int",
                        "writeable": true
                      }
                    ]
                  },
                  {
                    "identifier": "flow5",
                    "type": "node",
                    "children": [
                      {
                        "identifier": "enable",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "ip",
                        "type": "string",
                        "writeable": true
                      },
                      {
                        "identifier": "port",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "channels",
                        "type": "int",
                        "writeable": true
                      }
                    ]
                  },
                  {
                    "identifier": "flow6",
                    "type": "node",
                    "children": [
                      {
                        "identifier": "enable",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "ip",
                        "type": "string",
                        "writeable": true
                      },
                      {
                        "identifier": "port",
                        "type": "int",
                        "writeable": true
                      },
                      {
                        "identifier": "channels",
                        "type": "int",
                        "writeable": true
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}
JS


Syntax Details:

  • restApi.endpoints.methods.putSfp.request.content.contentSource: Added a new contentSourceType "treeToJson". This mode will try to generate a json file from the corresponding ember tree and send it to the device.
    • emberTree.children[Spf1].children[sfp].children[flows].type: Added a new tree type "nodeArray". This element can be used to generate a json array of the children. If a child is of type "node", the driver will generate an object array. This example may generate the following for the flows array:
{
  "sfp": {
    "filters": ...
    "video": { ...
    },
    "flows": [
      {
        "enable": 1,
        "ip": "239.1.2.3",
        "port": 12343,
        "channels": 4
      },
      {
        "enable": 1,
        "ip": "239.1.2.4",
        "port": 12344,
        "channels": 4
      },
      {
        "enable": 1,
        "ip": "239.1.2.5",
        "port": 12345,
        "channels": 4
      },
      {
        "enable": 1,
        "ip": "239.1.2.6",
        "port": 12346,
        "channels": 4
      },
      {
        "enable": 1,
        "ip": "239.1.2.7",
        "port": 12347,
        "channels": 4
      },
      {
        "enable": 1,
        "ip": "239.1.2.8",
        "port": 12348,
        "channels": 2
      }
    ]
  }
}
JS

Known Issues

There are currently no known issues with the implementation.