API – Documentation

Here you can access the old API Documentation, for software versions V2.7.10 and below.
Please consider updating the control unit to the newest software version and using the API as described here.

Getting started

This API was developed to enable customized control in the diverse machine control environments. The API provides programmatic access to read state and control the camera system.

Two web-based communication protocols are available. On the one hand, it is possible to set up a stateless connection via the standard HTTP Get or Post request and to fetch or set the desired data. On the other hand, an event-driven system can be developed via a websocket connection. In this way, the software programmed by the customer could react to changing information, which are synchronized in real time.

  • Http API
  • WebSocket API
  • Camera stream
  • Visual Backup
  • State Description
  • Code Examples

Http API

The http API is a RESTful API. The control unit of the Rotoclear C2 represents the server in the local network environment and the program is the client. Communication happens stateless between server and client. This means that the server does not know anything about the last requested data and even if the data is still up to date it will be sent again on request.

This API is ideal for writing a simple and small control program. It is also easy to test. The Get Requests URL can be entered directly in the browser in the URL input field, or it can be tested with postman or curl. All that is needed is a http Client and some understanding of the http protocol, url queries, the http headers and JSON format.

Connection

Http API can be accessed via both web servers on the control unit. In principle, the origin of the connection url is the same under which we can also call the web client in the browser. The path '/api' is appended to this url origin (see 'Connection URL examples'). Of course, the respective web server must be switched on in the connection settings (see http and https connection in menu). These connection settings also contain the port we need for our http client connection. Please note: For security reasons, the https connection is always recommended.

The API responds to two HTTP methods. The HTTP GET method can be used to set request details in the URL query. For practical reasons, it is also allowed to set parameters in the API (which will be explained below). With the HTTP POST method, more complex request structures can be mapped with a JSON formatted body.

Connection URL examples: 
    http://rotoclear.local:80/api
    https://rotoclear.local:443/api
    https://192.168.0.123:3000/api

Response:
    401 Unauthorized

Authentication and Authorization

Furthermore, we need also the API token from the settings. This is configurable after the activation of the API module. The system has an internal permissions system, which can assign different rights for different users. With the activation of the API module, an 'API-User' user is created in addition to the 'admin' user. The token set in the settings reflects the password of the 'API-User'.

Authentication via parameters in the url query:

The user and the password can be set as one parameter in the URL query. In this case, the keywords 'token' and 'password' are mapped to the same field of the user as password. If the user is not passed, the 'API-User' is assumed as default. (example: 'Authentication in URL Query'). This authetification variant has advantages and disadvantages. One disadvantage is that the token is readable in its raw form in the url query. One advantage is that a request can be made simply as URL text, as for example with the GET request by entering the url in browser.

If an http client connects only with this information, then all information authorized for the user is sent as response, since no further information and selection is provided.

Authentication in URL Query: 
    http://rotoclear.local:80/api?user=API-User&token=***
    https://rotoclear.local:443/api?token=***
    https://192.168.0.123:3000/api?password=***

Curl example:
    curl -X GET -G https://rotoclear.local:443/api -d token=***

Response:
    200 Success. 
    With JsonObject as description of the state in body of the response.

Simplified and formatted body example of the response body: 
    {
      "oct0":"69.7°C",
      "oct1":"80.0°C",
      "light0":false,
      "light1":false,
      "hasInternet":true,
      "macAddr":"00:15:5D:7E:D9:46",
      "hostname":"rotoclear",
      "netInfo":[
        {
          "name":"eth0",
          "description":"eth0",
          "macAddress":"00:15:5D:7E:D9:46",
          "gateway":"",
          "isServer":false,
          "dhcp":true,
          "dhcpServers":[],
          "connections":[{
              "address":"172.28.32.226",
              "netmask":"255.255.240.0",
              "broadcast":"172.28.47.255"
          }],
          "dhcpSelected":true,
          "staticIp":"192.168.214.221",
          "staticMask":"255.255.255.0",
          "staticGateway":"192.168.214.1",
          "staticDns":"8.8.8.8",
          "staticUseGateway":false,
          "staticUseDns":false
        }
      ],
      "pan0":{"x":50.31323414252154,"y":49.89594172736733},
      "pan1":{"x":50,"y":50},
      "pip":0,
      "psi0":"1712mbar",
      "psi1":"1008mbar",
      "psiSetpoint":"1150mbar",
      "changeVideoName":"",
      "changeImageName":"",
      "changePostName":"",
      "record":"stop",
      "recordTime":0,
      "rtspPort":1025,
      ...
    }

Authentication via Basic Authentication:

The second authentication variant is Basic Authentication. For this purpose, according to the RFC7617 standard, the 'Authorization' key is specified in the http header. The value of authorization key composes the text "Basic " and the base64 encoded 'username:password'. Further information should be taken from the documentation of the respective http client and used programming language.

Basic Authentication - Curl example:
    curl -X GET -G https://rotoclear.local:443/api \
        -u "API-User:token"

Response:
    200 Success. 
    With JsonObject as description of the state in body of the response.

Http Get method

Now that the connection and the authentication to the API was successful, we can go into some details about the requests. In the request with the http Get method, additional parameters can be added in the URL query. To get only the state of the system, the keyword 'get' can be used to list only the desired system state variables. The description of the state variables can be found at the end of this documentation (see: 'State Description'). All variables allowed to the user can be queried in this way. Unknown or unauthorized state variables are ignored by the API. This means that these values are not listed in the response.

Query selected state variables - URL example:
    https://rotoclear.local:443/api?token=***&get=[light0,record,recordTime,pan0]

Query selected state variables - Curl example:
    curl -X GET -G https://rotoclear.local:443/api \
        -d token=*** \
        -d get=[light0,record,recordTime,pan0]
    
Response:
    {
      "light0": true,
      "record": "stop",
      "recordTime": 0,
      "pan0": {
        "x": 50.26041666666666,
        "y": 50.0
      }
    }

The Get method can also be used to set values in the system state. Please note that complex and nested structure variables cannot be easily mapped in a query, so they will not work with a GET request. To set a variable, simply match its key to the value in the query. Since in the query the variables are written only in the form of text, these variables are converted internally into the respective data types. That means "true" or "false" becomes a JSON boolean, written-out numbers are converted into the respective JSON numbers as Integer or Float number and saturated. In addition, the values are validated and caught in a valid and defined range. After setting the variable, the updated state variables are listed in the response of the request.

Set state variables - URL example:
    https://rotoclear.local:443/api?token=***&light0=true&record=start

Set state variables - Curl example:
    curl -X GET -G https://rotoclear.local:443/api \
        -d token=*** \
        -d light0=true \
        -d record=start

Response:
    {
      "light0": true,
      "record": "stop",
    }
The system could respond with a "record": "stop" if, for example, no storage medium was selected for recording.

Http Post method

There are also some slightly more complex data types in the system state. These include for example network, time, stream pan settings, etc. If you want to set these more complex data types, you can use the http post method. To do this, the settings in JSON format are passed to the request in the body.

Set pan for first camera head - Post Request with a JSON body:
    curl -X POST https://rotoclear.local:443/api \
      -u "API-User:***" \
      -H "Content-Type: application/json" \
      -d '{"pan0": {"x": -10.5, "y": -10}, "zoom0": 20000}'

Response:
      {
        "pan0": {
          "x": 39.5,
          "y": 40.0
        },
        "zoom0": 20000
      }
While the control of the camera heads, i.e. the pan and the zoom 
are calculated relative to the current value, the return value 
of the API is always the absolute value currently set.

For simplicity, values can also be queried via the post method. To do this, the get key must be matched with an array of keys in string form.

Furthermore, it should be mentioned that with one request state getter and setter can be sent at the same time. Usually these are executed in the written order. The same applies to the get requests, where the order of the query parameters is considered.

Query state - Post Request with a JSON body:
    curl -X POST https://rotoclear.local:443/api \
      -u "API-User:***" \
      -H "Content-Type: application/json" \
      -d '{"get": ["light0","record","recordTime","pan0"]}'

Response:
    {
      "light0": true,
      "record": "stop",
      "recordTime": 0,
      "pan0": {
        "x": 50.26041666666666,
        "y": 50.0
      }
    }

WebSocket API

The websocket API is suitable for programming an event-based system. The API is based, as the name says, on the extended http API protocol called websocket. With a websocket a permanent connection can be established. To understand the communication over the websocket with the API we must consider the following points.

1. communication data and format:
The API communicates like the http API internally with JSON formatted data (there are some internal exceptions, but these should never occur in normal usage). This means that incoming messages to the websocket client will 'always' be JSON objects. In these objects one or more state variables of the system can be listed. This also means that the websocket client must also send its control messages in JSON format.

2. subscription:
When a connection is established with the API and authorized, all variables of the system authorized to the user are automatically subscribed to. This means that first, all these variables are packaged in JSON and sent to the client as an initial state, and then second, whenever the state changes, the corresponding variables are sent again to the client in real time. This way a system can be built which is synchronized in real time with the control unit.

3. control:
It is also possible for the websocket client to participate in the state of the system. As with the http Post request, the websocket can send JSON formatted messages. These are evaluated and set in real time. The data type as well as the write permission for the variables must be considered here. See the state table at the end of the document.

Connection

The websocket connections reside in the same endpoints as the http API connections. Again, both web servers (http and https web servers) are accessible for this connection. We only must note that "ws" must be written as protocol instead of "http".

For more information about websocket connections, please refer to documentation of the websocket and the respective development programming language of your client system.

Connection URL examples: 
    ws://rotoclear.local:80/api
    wss://rotoclear.local:443/api
    wss://192.168.0.123:3000/api

In Javascript:

const socket = new WebSocket("wss://rotoclear.local:443/api");

Response:
    401 Unauthorized

Authentication and Authorization

For authentication and authorization of the connection, the token and the user must be set in the url query. See also the authentication of the http API in the paragraph: Authentication in URL Query.

Create connection to the WebSocket API in Javascript:

const token = "***"; // query conform encoding should be considered here
const socket = new WebSocket("wss://rotoclear.local:443/api?token=" + token);

// add callbacks
socket.onerror = function(error){ console.error(error); };
socket.onmessage = function(evt) { 
  if (typeof evt.data === "string") {  
    var jsonMsg = JSON.parse(evt.data);
    console.debug(jsonMsg);
    // The first message will represent the entire allowed state. The following ones will represent the updates.
  }
}

Example

Create connection to the WebSocket API in Nodejs:

var WebSocket = require('websocket').w3cwebsocket;

const token = "***"; // query conform encoding should be considered here
const socket = new WebSocket("wss://rotoclear.local:443/api?token=" + token);

function sendToAPI(message) {
  // stringify json message
  connection.send(JSON.stringify(message));  
}

connection.onopen = function() {
  // now we can send messages to api
  sendToAPI({ "light0": true });
};

connection.onerror = function(error) { console.error(error); };

connection.onmessage = function(evt) { 
  if (typeof evt.data === "string") {  
    var stateMsg = JSON.parse(evt.data);
    console.debug(stateMsg);

    // Use data from api to control your system
    // .... 
  } 
};

Camera stream

The camera stream can also be processed via the http requests. Please note that authentication with the corresponding credentials (username and password) is required in the http request to access the camera stream. For authentication and authorization see http API authentication in paragraph: Authentication in URL query.

1. Retrieving a JPEG image:
A JPEG image can be obtained by making an http GET request. To do this, the path '/camera.jpeg' and the authentication must be added to the connection.

Request Image: 
    http://rotoclear.local:80/camera.jpeg?user=admin&password=***

2. Streaming MJPEG:
For streaming MJPEG, the content type 'multipart/x-mixed-replace' is used. The server sends a continuous series of JPEG images in response to the http request. The content type of each individual image is specified as 'Content-Type: image/jpeg'.
The server will respond with a continuous series of JPEG images, transmitted in the body of the http response. Each image has the content type 'image/jpeg' and is sent in a separate http message. The client can process the MJPEG stream by extracting and displaying each individual JPEG image.

Request MJPEG: 
    http://rotoclear.local:80/camera.mjpeg?user=admin&password=***

Visual Backup

Visual Backup is a feature for visually documenting work processes through a series of video recordings.
The length of each recording varies based on the settings and storage capacity.
This feature is designed to allow reviewing past operations within a specified timeframe.

An algorithm deletes the oldest approved videos whenever there is an overflow of recorded video hours or when the storage capacity is low.

In Visual Backup mode, you can add a description to a video by using tags.
These tags serve to secure and visualize specific events and also ensure that the tagged videos cannot be deleted by the backup algorithm.
The tags can be removed in the Backup gallery, allowing the algorithm to delete the file again.

Additionally, users can choose from several storage media options for backup and manual recording.
It is important to distinguish between Visual Backup and manual recording in the media selection.
Although you can view either media type in the Backup Gallery, the Visual Backup write and delete algorithms apply only to the selected backup media type.
Therefore, changing the backup media in the settings must be done carefully.

Additionally, note the following general conditions.
a. The delete algorithm is activated when initially starting Visual Backup and when the software splits its recordings into separate file.
b. When starting Visual Backup, ensure that at least one hour is available for recording or can be freed up by the algorithm before initiating further recording.

Calculation

Calculation of the backup capacity in steps.

1. scan storage capacity

example output:
  total:  125828988928
  totalStr: 117.187 GB
  used: 65710194688
  usedStr: 61.197 GB
  free: 60118794240
  freeStr: 55.990 GB

2. calculate possible video time capacity of storage

// The possible capacity is calculated based on the
// recording resolution, frames per second and quality
// as well as the free memory of the storage.

function(
  resolution,
  fps,
  quality,
  freeStorageCapacity
) → remainingBackupVideoTimeInSeconds


example:
  function(
      "HD",
      30,
      75,
      60118794240
  ) → 14313 // this is approx. 3h 58min

3. calculate recorded backup capacity time

// We iterate over all noted backup files that
// can be found and deleted and add up the duration

recordedBackupCapacityInSeconds = sum(
    file.where(
      'file exists in backup storage' and 
      'can be deleted'
    )
  )

4. calculate the total backup capacity

storageBackupCapacityInSeconds =  
    remainingBackupVideoTimeInSeconds + 
    recordedBackupCapacityInSeconds

We can find this value in the Visual Backup menu unter the storage management with the name 'Backup capacity'. This value should be generally bigger or equal than the remaining capacity of the storage.

State Description

The following table describes the state variables. Please note that some settings are dependent on each other. Accordingly, the system will validate the inputs and trigger notifications under certain circumstances.

Legend

r - readable
w - writeable
[x,y] - interval of valid values.

API Key Value
Datatype
Permissions Description
cam0Exists Boolean r existence of the first camera head
cam1Exists Boolean r existence of the second camera head
cameraSwitch Boolean rw selection of the current streaming and recording camera head.
false -> first camera is selected
true -> second camera is selected
lineRateA String r data transmission rate of the first camera head
lineRateB String r data transmission rate of the second camera head
ver0 String r hardware and software version of the first camera head
ver1 String r hardware and software version of the second camera head
autoRotate0 Boolean rw automatic alignment of the first camera head
false -> first camera is selected
true -> second camera is selected
autoRotate1 Boolean rw automatic alignment of the second camera head
false -> first camera is selected
true -> second camera is selected
dictRotation0 Boolean rw first camera head disk rotation
dictRotation1 Boolean rw second camera head disk rotation
rpm0 Integer r read rotation speed setpoint of the first camera head
rpm1 Integer r read rotation speed setpoint of the second camera head
RPM0 Integer r measured rotation speed of the first camera head
RPM1 Integer r measured rotation speed of the second camera head
light0 Integer rw first camera head light
false -> disabled
true -> enabled
light1 Integer rw second camera head light
false -> disabled
true -> enabled
downstat String r state of the 'update process' working in the background
fpgaTemp String r temperature of the FPGA in the control box
exposure Boolean rw automatically aligned exposure of the picture
false -> disabled
true -> enabled
whiteBalance Boolean rw automatically white balance of the picture
false -> disabled
true -> enabled
noiseSuppression Boolean rw automatically noise suppression
false -> disabled
true -> enabled
redGain Integer [-128,127] rw red gain value
works only if whiteBalance is disabled
blueGain Integer [-128,127] rw blue gain value
works only if whiteBalance is disabled
brightness Integer [-7,7] rw brightness of the picture
works only if exposure is disabled
expo Number [0.01,1000.0] rw exposure time [in ms]
works only if exposure is disabled
gain Integer [0,42] rw gain
works only if exposure is disabled
sharpness Integer [1,15] rw sharpness of the picture
saturation Number [-7,7] rw color saturation of the picture
contrast Number [1,2.5] rw contrast of the picture
hdmiConnected Boolean r indicates whether a monitor is connected to the control box
hdmiName String r name of the monitor
cfg30 String r rate of the first optical sensor of the first camera head (dependent on the quality of the connection)
"0" ≙ no optical sensor found
"30" ≙ optical sensor with 30fps found
"60" ≙ optical sensor with 60fps found
cfg40 String r rate of the second optical sensor of the first camera head (dependent on the quality of the connection)
"0" ≙ no optical sensor found
"30" ≙ optical sensor with 30fps found
"60" ≙ optical sensor with 60fps found
cfg31 String r rate of the first optical sensor of the second camera head (dependent on the quality of the connection)
"0" ≙ no optical sensor found
"30" ≙ optical sensor with 30fps found
"60" ≙ optical sensor with 60fps found
cfg41 String r rate of the second optical sensor of the second camera head (dependent on the quality of the connection)
"0" ≙ no optical sensor found
"30" ≙ optical sensor with 30fps found
"60" ≙ optical sensor with 60fps found
oct0 String r temperature of the first camera head
oct1 String r temperature of the second camera head
cam0SelectedSensor Integer [0,1] rw selected optical sensor of the first camera head
Be careful, if your head does not have 2 optical sensors, it will mirror your image!
cam1SelectedSensor Integer [0,1] rw selected optical sensor of the second camera head
Be careful, if your head does not have 2 optical sensors, it will mirror your image!
language String rw current selected language in menu
Please note that only the selection of languages from the menu is valid.
licenseConfig Json Array r list of feature configurations in system
licenseModules Json Array r list of modules in system
hasInternet Boolean r control box has internet access
macAddr String r mac address of the first network device in hardware
hostname String r currently only read only access to hostname
netInfo Json Array r list network devices and settings
zoom0 Integer [0,31424] rw zoom of first camera head
Please note: For algorithmic reasons, a relative value is always assumed when setting the value. But the response is always the absolute value.
zoom1 Integer [0,31424] rw zoom of second camera head
Please note: For algorithmic reasons, a relative value is always assumed when setting the value. But the response is always the absolute value.
pan0 Json Object
{
  "x": Number,
  "y": Number
}
rw pan of the first camera head
Please note: For algorithmic reasons, a relative value is always assumed when setting the value. But the response is always the absolute value.
The values x and y are only valid in interval of [0.0,100.0]
pan1 Json Object
{
  "x": Number,
  "y": Number
}
rw pan of the second camera head
Please note: For algorithmic reasons, a relative value is always assumed when setting the value. But the response is always the absolute value.
The values x and y are only valid in interval of [0.0,100.0]
pip Number [0,4] rw picture in picture mode selection
0 ≙ only current camera
1 ≙ pip is top left
2 ≙ top right
3 ≙ bottom left
4 ≙ bottom right
psi0 String r sealing air of first camera head in bar
psi1 String r sealing air of second camera head in bar
psiSetpoint String r default sealing air set point in bar
changeVideoName String rw prefix of the recorded video file
changeImageName String rw prefix of the recorded image file
changePostName String rw postfix of the recorded file
changeBackupPostName String rw postfix of the recorded backup file
record String rw state of recording
options: "start", "pause", "release" or "stop"
please note: that the recording requires some conditions such as the presence of the storage medium and sufficient storage space
takePicture Boolean w trigger snapshot
recordTime Number r traced time of current video recording
rtspPort Number rw port of rtsp server
rtspOn Boolean rw rtsp server running
rtspStatus Json Object r status of rtsp server
diskStorages Json Object r list of detected usb storages
netStorages Json Object r list of setted network storages
backupStorage Json Object r selected visual backup storage description
backupStorage String w select visual backup storage with uuid (select one id in diskStorages or netStorages)
recordingStorage Json Object r selected manual recording storage description
recordingStorage String w select manual recording storage with uuid (select one id in diskStorages or netStorages)
alignmentStream0 String rw rotate stream of first camera head
"0" ≙ 0°
"1" ≙ 180°
alignmentStream1 String rw rotate stream of second camera head
"0" ≙ 0°
"1" ≙ 180°
backupResolution String rw backup recording and stream resolution
"FullHD": 1920x1080
"HD": 1280x720
recordingResolution String rw recording and stream resolution
"4K": 3840x2160
"FullHD": 1920x1080
"HD": 1280x720
recordingFps Integer rw recording and stream frames per second.
options: 1, 5, 10, 15, 30, 60
backupFps Integer rw backup recording and stream frames per second.
options: 1, 5, 10, 15, 30
recordingPictureQuality Integer [1,100] rw quality of jpeg compressor
backupPictureQuality Integer [1,100] rw quality of jpeg compressor
mjpgStreamIsOpen Boolean rw enable or disable the stream for clients without connection token
recordingWithTimeStamp Boolean rw write time into stream and recording
recordingWithDateStamp Boolean rw write date into stream and recording
backupWithTimeStamp Boolean rw write time into stream and backup recording
backupWithDateStamp Boolean rw write date into stream and backup recording
systemDescription Json Object r hardware and system description of control box
time Json Array of numbers r systems time [year,month,day,hours,minutes,seconds]
timezone String rw selected timezone
ntpHost String rw address ot the ntp server
ntpStatus Json Object r State of last connection try to ntp server
ntpSync Boolean rw enable ntp syncronization
seconds Integer r epoch time seconds
connectionUrls Json Object r list of detected and assumed possible connections
userAuthentication Json Object rw enables password authentication in clients
swVersion String r current software version
fmVersion String r current firmware version
httpOn Boolean rw http webserver run setting
httpsOn Boolean rw https webserver run setting
httpPort Integer [1,65000] rw http webserver port
httpsPort Integer [1,65000] rw https webserver port
httpStatus Json Object r http webserver status
httpsStatus Json Object r https webserver status
httpsCertificate Json Object r certificate description
backupActive Boolean rw Visual Backup recording is on/off
backupUseCompleteSpace Boolean rw enables the Visual Backup storage strategy to use the whole storage (the oldest files are deleted only when there is less than 1 hour of memory left)
backupMaximumRecordingTimeCapacity Integer rw if backupUseCompleteSpace is off, then this value is used to limit the space of stored data
backupStoredFileDuration String r describes the complete stored backup video duration, that can be found in current storages
backupFileCapacity String r describes the current overwritable stored backup video duration
backupRemainingCapacitySeconds String r describes the free space of current backup storage in video time seconds as number value
backupRemainingCapacityHours String r describes the free space of current Visual Backup storage in video time hours as number value
backupRemainingCapacity String r describes the free space of current Visual Backup storage in video time as text (example '15:35h')
storageBackupCapacity String r describes the limit of the current Visual Backup storage (backupRemainingCapacity + backupFileCapacity)
createTag Json Object
{
creationTime:
<unix seconds as number>
or
<timestamp formatted as string:
"yyyy-MM-dd'T'HH:mm:sszzz">,
title: <string>,
note: <string>,
}
w Create a tag. If currently backup is not running and not creationTime is set in the message, it starts the recording immediately. All parameters in the json request object are optional.

Code examples

These code examples are designed to help you getting started using our API.

  • Node.js
  • C#
  • NIM
  • Python

Node.js

#!/usr/bin/env node

// Example for Nodejs - JS
//
// 1. Connect to websocket-server
// 2. Check camera 1 is connected
// 3. If camera 1 is connected toggle the light
// 4. Take a jpg image and save it as file
// 5. Close connection
//
// Install dependencies:
//   npm install websocket
//


const W3CWebSocket = require('websocket').w3cwebsocket;
const http = require('http');
const fs = require('fs');

const RotoclearIp = "192.168.178.61"
const RotoclearApiPort = "80"
const ApiToken = "1a2B3c4D5e6f7G8h"
const WebsocketApiUrlWithAuth = "ws://" + RotoclearIp + ":" + RotoclearApiPort + "/api?token=" + ApiToken
const HttpCameraImageUrlWithAuth = "http://" + RotoclearIp + ":" + RotoclearApiPort + "/camera.jpeg?user=API-User&token=" + ApiToken
const imageName = 'myNewImage.jpg'

console.log("try to establish connection to ", WebsocketApiUrlWithAuth)
var connection = new W3CWebSocket(WebsocketApiUrlWithAuth);

function sendToAPI(message) {
  // Send message to api server. Only stringified json object is accepted
  connection.send(JSON.stringify(message));
}


connection.onerror = function (err) {
  console.log('Connection error', err.toString());
};

connection.onopen = function () {
  console.log('Connection successful established');
};

connection.onclose = function (ev) {
  console.log('Client closed', ev.reason);
};

connection.onmessage = function (ev) {
  if (typeof ev.data === "string") {
    // if data is of type string, then it is json
    var api_message = JSON.parse(ev.data);

    if (api_message["cam0Exists"]) {
      if(api_message["light0"]) {
        sendToAPI({ "light0": false });
      } else {
        sendToAPI({ "jpeg": true });
      }

      http.get(HttpCameraImageUrlWithAuth, (res) => {
        let data = [];
        console.log('Status Code:', res.statusCode);
        res.on('data', (chunk) => {
          data.push(chunk);
        });
        
        res.on('end', () => {
          const imageBuffer = Buffer.concat(data);
          fs.writeFileSync(imageName, imageBuffer);

          process.exit()
        });
        
      }); 
    } else {
      console.log("No camera head detected")
      process.exit()
    }
  } 
};

C#

// Dotnet c# API Example
//
// 1. Connect to websocket-server
// 2. Check camera 1 is connected
// 3. If camera 1 is connected toggle the light
// 4. Take a jpg image and save it as file
//
// Install dotnetSDK:
//   see:  https://docs.microsoft.com/de-de/dotnet/core/install
// 
// Init project in current directory:
//   dotnet new console
// 
// copy the content to your Program.cs and replace the namespace "dotnet_websocket_api_example" with yours

using System.Text;
using System.Net.WebSockets;
using System.Text.Json;
using System.Net;

namespace dotnet_websocket_api_example
{
  class Program
  {
    const string ServerIp = "192.168.178.61";
    const int ServerPort = 80;
    const string APIToken = "1a2B3c4D5e6f7G8h";


    public static Task SendString(ClientWebSocket ws, String data)
    {
      var encoded = Encoding.UTF8.GetBytes(data);
      var buffer = new ArraySegment<Byte>(encoded, 0, encoded.Length);
      return ws.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
    }

    public static async Task<String> ReadString(ClientWebSocket ws)
    {
      ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[32000]);

      using (var ms = new MemoryStream())
      {
        while (true)
        {
          WebSocketReceiveResult result = await ws.ReceiveAsync(buffer, CancellationToken.None);
          ms.Write(buffer.ToArray(), buffer.Offset, result.Count);
          if (result.EndOfMessage) {
            break;
          }
        }

        ms.Seek(0, SeekOrigin.Begin);
        using (var reader = new StreamReader(ms, Encoding.UTF8))
        {
          return reader.ReadToEnd();
        }
      }
    }

    static async Task Main(string[] args)
    {
      // Define the cancellation token.
      using (var socket = new ClientWebSocket())
      {

        try
        {
          await socket.ConnectAsync(new Uri("ws://" + ServerIp + ":" + ServerPort + "/api?token=" + APIToken), CancellationToken.None);

          string systemStateMessage = await ReadString(socket);
          JsonDocument doc = JsonDocument.Parse(systemStateMessage);
          var systemStateJson = doc.RootElement;

          System.Console.WriteLine(systemStateJson.ToString());

          if (!systemStateJson.GetProperty("cam0Exists").GetBoolean()) {
            // toggle light
            if (systemStateJson.GetProperty("light0").GetBoolean()) 
            { 
              await SendString(socket, "{ \"light0\": false }");
            }
            else
            {
              await SendString(socket, "{ \"light0\": true }");
            }

            // # get jpeg and save it
            using (var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }))
            {
                HttpResponseMessage response = await client.GetAsync("http://" + ServerIp + ":" + ServerPort + "/camera.jpeg?user=API-User&token=" + APIToken);
                var jpgBytes = await response.Content.ReadAsByteArrayAsync();
                File.WriteAllBytes("streamImage.jpg", jpgBytes);
            }
          }
          else
          {
            System.Console.WriteLine("No camera head detected");
          }
        }
        catch (Exception ex)
        {
          Console.WriteLine($"ERROR - {ex.Message}");
        }
      }
    }
  }
}

NIM

# Example in NIM - Control light via websocket api
#
# 1. Connect to websocket-server
# 2. Check camera 1 is connected
# 3. If camera 1 is connected then toggle the light
# 4. Take a jpg image and save it as file
# 5. Close connection
#
# Install dependencies:
#   nimble install ws
#

import std/[
    strformat,
    strutils,
    json,
    asyncdispatch,
    httpclient
  ]
import ws

const
  rotoclearIp = "192.168.178.61" 
  rotoclearApiPort = "80" 
  apiToken = "1a2B3c4D5e6f7G8h"
  wsUrlWithAuthInQuery = fmt("ws://{rotoclearIp}:{rotoclearApiPort}/api?token={apiToken}")
  streamImageUrlWithAuthInQuery = fmt("http://{rotoclearIp}:{rotoclearApiPort}/camera.jpeg?user=API-User&token={apiToken}")


proc runProcess() {.async.} = 
  # create connection
  let conn = await newWebSocket(wsUrlWithAuthInQuery)

  let
    # after a successful authentication the response will be the whole state
    response = await conn.receiveStrPacket()
    currentStateJson = parseJson(response)

  # print state in console
  echo currentStateJson.pretty

  if currentStateJson.hasKey("cam0Exists"): 
    if currentStateJson["cam0Exists"].getBool():
      if currentStateJson["light0"].getBool(): 
        let message = %*{ "light0": false }
        await conn.send($message)
      else:
        let message = %*{ "light0": true }
        await conn.send($message)
      
      # get jpeg and save it
      let
        client = newHttpClient()
        response = client.getContent(streamImageUrlWithAuthInQuery)

      writeFile("currentImage.jpeg", response)
    else:
      echo "No camera head detected"
  conn.close()

waitFor runProcess()
# Example in NIM - Use http api to get and set data
#
# 1. Connect to websocket-server
# 2. Fetch some information from the system (eg. light0, record, recordTime, pan0)
# 3. Disable light and move pan cursor from current position via post request
# 

import std/[strformat, json, httpclient]

const
  rotoclearIp = "192.168.178.61" 
  rotoclearApiPort = "80" 
  apiToken = "1a2B3c4D5e6f7G8h"
  urlWithAuthInQuery = fmt("http://{rotoclearIp}:{rotoclearApiPort}/api?token={apiToken}")

let
  client = newHttpClient()
  response = client.getContent(urlWithAuthInQuery & "&get=[light0,record,recordTime,pan0]")
  jsonResponse = response.parseJson()

echo jsonResponse.pretty()

# disable light and move pan cursor from current position via post request
let
  message = %*{ 
    "light0": false,
    "pan0": { # relative values
      "x": -20.0, 
      "y": -30.0
    }
  }

echo client.postContent(urlWithAuthInQuery, $message)

Python3

#!/usr/bin/python3

# Example in Python3
#
# 1. Connect to websocket-server
# 2. Check camera 1 is connected
# 3. If camera 1 is connected then toggle the light
# 4. Take a jpg image and save it as file
# 5. Close connection
#
# Install dependencies:
#   pip install websocket-client
#   pip install requests
#   pip install json
#

from websocket import create_connection
import requests
import json

ROTO_CLEAR_IP = "192.168.178.61"
ROTO_CLEAR_PORT = "80"
MY_API_TOKEN = "1a2B3c4D5e6f7G8h"

WEBSOCKET_API_URL_WITH_AUTH = "ws://" + ROTO_CLEAR_IP + ":" + ROTO_CLEAR_PORT + "/api?token=" + MY_API_TOKEN
HTTP_CAMERA_IMAGE_URL_WITH_AUTH = "http://" + ROTO_CLEAR_IP + ":" + ROTO_CLEAR_PORT + "/camera.jpeg?user=API-User&token=" + MY_API_TOKEN

ws = create_connection(WEBSOCKET_API_URL_WITH_AUTH)

# after the connection the api response is the whole system state
response = ws.recv()
systemState = json.loads(response)

# print state in console
print(systemState)

if systemState["cam0Exists"]:
    # toggle light
    if systemState["light0"]:
        jsonText = json.dumps({"light0": False})
        ws.send(jsonText)
    else:
        jsonText = json.dumps({"light0": True})
        ws.send(jsonText)

    # get jpeg and save it
    imageResponse = requests.get(HTTP_CAMERA_IMAGE_URL_WITH_AUTH)

    f = open("myCurrentImg.jpg", "wb")
    f.write(imageResponse.content)
    f.close()
else:
    print("No camera head detected")

ws.close()
#!/usr/bin/python3

# Example in Python3 - Use http api to get and set data
#
# 1. Connect to websocket-server
# 2. Fetch some information from the system (eg. light0, record, recordTime, pan0)
# 3. Disable light and move pan cursor from current position via post request
#
# Install dependencies:
#   pip install requests
#   pip install json
#

import requests
import json

ROTO_CLEAR_IP = "192.168.178.61"
ROTO_CLEAR_PORT = "80"
MY_API_TOKEN = "1a2B3c4D5e6f7G8h"
HTTP_API_URL_WITH_AUTH = "http://" + ROTO_CLEAR_IP + ":" + ROTO_CLEAR_PORT + "/api?user=API-User&token=" + MY_API_TOKEN

response = requests.get(HTTP_API_URL_WITH_AUTH + 
                            "&get=[light0,record,recordTime,pan0]")
jsonResponse = json.loads(response.content)

print(jsonResponse)

# disable light and move pan cursor from current position via post request
message = json.dumps({ 
    "light0": False,
    "pan0": { # relative values
        "x": -20.0, 
        "y": -30.0
    }
})

response = requests.post(HTTP_API_URL_WITH_AUTH, message)
print(response.content)