Trafic Light Sample - aliconnect/aliconnect.sdk GitHub Wiki

AIM Control Create Custom Application

This example is based on a Logic Control for a trafic light conform the Dutch Tunnel Standard LTS of the Dutch Government

Install aim-server

Open command prompt. Hit windows+R and enter cmd.

Create project folder sample1

md sample1
cd sample1

Create a package.json file with npm.

npm init

Install the package aim-server.

npm i aim-server

or create a mklink to your development aim-server folder

mklink /d node_modules c:\aliconnect\node_modules

Create file secret.json and set following attributes

  • client_secret: Your client_secret code from the Aliconnect platform. For this example the client_secret is ea877497-86a1-49f3-a69a-ef4b0287df82
{
    "client_secret": "ea877497-86a1-49f3-a69a-ef4b0287df82"
}

Create webapplication with API request to webserver

Control config file control1.json

  1. Create file control1.json and set following attributes
  • debug: true will enable debug message.
  • secret: Filename of secret file. Note that the filename secret.json is read protected through the webserver.
  • access_token: This is an access_token received during the authorization process. This token is used for the sample. Normaly do not enter this code in your config.
  • http: configure the HTTP of the current device.
    • port: For the control application we use port 1341
    • key: Optional file reference to a SSL certificate (not used within this sample)
    • cert: Optional file reference to a SSL certificate key (not used within this sample)
    • ca: Optional file reference to a SSL certificate (not used within this sample)
  • ws: Websocket configuration with websocket server. This is the websocket server address of the aim message server in a server based network.
    • url: websocket server URL. Can be cloud wss://aliconnect.nl:444 or local aim server f.e. unsecure ws://192.168.0.201:81 or secure wss://192.168.0.201:444.
{
    "debug": true,
    "secret": "./secret.json",
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJzaGEyNTYifQ.eyJhdWQiOjF9.98zaT3r4KqJD4phz9RhQE4JffdLO_b2bZ7fOZutizFo",
    "http": {
        "port": 1341
    },
    "ws": {
      "url": "ws://localhost:1340"
    }
}

Control NodeJS application

Create file control1.js

Require the aim-server module

aim = require('aim-server');

Extend the aim module with the API specification conform the Open API Standard 3.0.1.

  • api
    • openapi: OAS version 3.0.1
    • info : See OAS documentation for more information.
    • paths : See OAS documentation for more information.
      • Control(id)/SetState(state) : Specification of a API url. See OAS documentation for more information.
        • POST : Method POST within the url
          • operationId: Name of operation that will be executed with the described parameters extracted from the url.
    • components : See OAS documentation for more information.
      • schemas : See OAS documentation for more information.
        • Control : Definition of schema Control
aim.extend ({
    api: {
        "openapi": "3.0.1",
        "info": {
            "title": "Control",
            "description": "Control application",
            "contact": {
                "email": "[email protected]"
            },
            "version": "1.0.0"
        },
        "paths": {
            "Control(id)/SetState(state)": {
                "POST": {
                    "tags": [],
                    "summary": "",
                    "description": "Set output state",
                    "operationId": "setControl",
                    "parameters": [
                        { "name": "id", "in": "path", "description": "ID of output", "required": true, "schema": { "type": "integer", "format": "int64" } },
                        { "name": "state", "in": "path", "description": "State of output", "required": true, "schema": { "type": "boolean" } }
                    ],
                    "responses": {
                        "200": { "description": "Successful operation", "content": {} },
                        "400": { "description": "Invalid output supplied", "content": {} }
                    },
                    "security": [
                        { "api_key": [] }
                    ]
                }
            }
        },
        "components": {
            "schemas": {
                "Control": {
                    "type": "object",
                    "properties": {
                        "state": {
                            "type": "string"
                        }
                    }
                }
            }
        }
    }
});

The API referense to the operationID setOutput. This operation is called with the arguments id and state. Now extend the aim platform with the refered operation.

aim.extend ({
    operations : {
        setControl : function (id, state) {
            console.log(`The requested state of control ${id} is set to ${state}`);
            setTimeout(function() {
                ws.request({url: `Control(${id})`, method: "PATCH", body: { state: state } });
            },1000);
        	return { status: 200 }; // OK
        }
    }
});

Create Control Web Application

  1. Create folder sample1\js
  2. Create file sample1\js\hmi.js.
  3. Create folder sample1\css.
  4. Create file sample1\css\hmi.css.
  5. Create file sample1\hmi.html.

hmi.js

We will use the aim http.request function. This function is called with the following arguments

  1. Request parameters as an object containing the following properties
    • url: url of the request (required)
    • method: method of the request, GET, POST, PATCH or DELETE (required)
    • headers: headers as object (optional)
    • body: body object send with request POST and PATCH
  2. Callback response function with arguments
    1. res: JSON object response with state f.e. {"state":200}.
setState = function(id,state) {
    http.request({ url: `/api/Control(${id})/SetState(${state})`, method: 'POST' }, function(res) {
        console.log(`Control state set`);
    });
}

hmi.html

<!doctype html>
<html>
<head>
	<meta charset="utf-8">
	<title>HMI</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<script src="node_modules/aim-server/js/lib.js"></script>
    <script src="node_modules/aim-server/js/main.js"></script>
    <script src="js/hmi.js"></script>
    <link rel="stylesheet" href="css/hmi.css" />
</head>
<body>
    <h1>HMI</h1>
    <button onclick="setState(1,'red');">Request state red</button><br />
    <button onclick="setState(1,'yellow');">Request state yellow</button><br />
    <button onclick="setState(1,'green');">Request state green</button><br />
    <button onclick="setState(1,'white');">Request state off</button><br />
</body>
</html>

Start Control Application

node control
http://localhost:1341/hmi

ow click on the button Request state red and check if command prompt logs The requested state of control 1 is set to red.

How does it work

What we see is the followin proces

  1. The user clicks on the button
  2. The button onclick event executes the function setState with arguments id = 1 and state = red in the javascript js/hmi.js file
  3. This function executes a HTTP request with url = /api/Output(1)/SetState(1) and method = POST.
  4. The webserver receives the HTTP request and will lookup the API call in the API configuration. The request url /api/Output(1)/SetState(1) is find in de api/paths as Output(id)/SetState(state).
  5. The API configuration referce to operationId setControl.
  6. The operationId setControl is found in the aim.operations code of control1.js. It is executed with the configured parameters id and state
  7. This function returns a response { status: 200 }
  8. The response is send back to the HTTP request done by the HMI aplication function http.request in the setControl function.

Add central server

We will create a central server

server.json

{
    "debug": true,
    "secret": "./secret.json",
    "http": {
        "port": 1340
    }
}

server.js

aim = require('aim-server');
aim.extend ({
    api: {
        "openapi": "3.0.1",
        "info": {
            "title": "Server",
            "description": "Server application",
            "contact": {
                "email": "[email protected]"
            },
            "version": "1.0.0"
        },
        "paths": {
            "Control(id)/SetState(state)": {
                "POST": {
                    "tags": [],
                    "summary": "",
                    "description": "Set output state",
                    "operationId": "setControl",
                    "parameters": [
                        { "name": "id", "in": "path", "description": "ID of output", "required": true, "schema": { "type": "integer", "format": "int64" } },
                        { "name": "state", "in": "path", "description": "State of output", "required": true, "schema": { "type": "boolean" } }
                    ],
                    "responses": {
                        "200": { "description": "Successful operation", "content": {} },
                        "400": { "description": "Invalid output supplied", "content": {} }
                    },
                    "security": [
                        { "api_key": [] }
                    ]
                }
            }
        },
        "components": {
            "schemas": {
                "Output": {
                    "type": "object",
                    "properties": {
                        "state": {

                        }
                    }
                }
            }
        }
    },
    operations : {
        setControl : function (id, state) {
            console.log(`The requested state ${state} for control ${id} is send`);
            wss.request({url: `Control(${id})/SetState(${state})`, method: "POST", body: { state: state } });
        	return { status: 200 }; // OK
        }
    }
});

gui.html

  1. Create folder sample1\js
  2. Create file sample1\js\hmi.js.
  3. Create folder sample1\css.
  4. Create file sample1\css\hmi.css.
  5. Create file sample1\hmi.html.
<!doctype html>
<html>
<head>
	<meta charset="utf-8">
	<title>Sample 1</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<script src="node_modules/aim-server/js/lib.js"></script>
    <script src="node_modules/aim-server/js/main.js"></script>
    <script src="js/gui.js"></script>
    <link rel="stylesheet" href="css/gui.css" />
</head>
<body>
    <h1>GUI</h1>
    <button onclick="setOutput(1,'red');">SetOutput 1 to red</button><br />
    <button onclick="setOutput(1,'yellow');">SetOutput 1 to yellow</button><br />
    <button onclick="setOutput(1,'green');">SetOutput 1 to green</button><br />
    <button onclick="setOutput(1,'white');">SetOutput 1 to off</button><br />
</body>
</html>

js/gui.js

setOutput = function(id,state) {
    ws.request({ url: `/api/Control(${id})/SetState(${state})`, method: 'POST' }, function(res) {
        console.log(`Response Control(${id})/SetState(${state})`,res);
    });
}
aim.extend({
    config: {
        access_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJzaGEyNTYifQ.eyJhdWQiOjF9.98zaT3r4KqJD4phz9RhQE4JffdLO_b2bZ7fOZutizFo",
        ws: {
            url: "ws://localhost:1340",
        }
    },
    operations : {
        updateValue : function (id, body) {
            document.body.style.background = body.state;
        	return { status: 200 }; // OK
        }
    },
    api: {
        paths: {
            "Control(id)": {
                "PATCH": {
                    "tags": [],
                    "summary": "",
                    "description": "Set output state",
                    "operationId": "updateValue",
                    "parameters": [
                        { "name": "id", "in": "path", "description": "ID of output", "required": true, "schema": { "type": "integer", "format": "int64" } },
                        { "name": "body", "in": "path", "description": "State of output", "required": true }
                    ],
                    "responses": {
                        "200": { "description": "Successful operation", "content": {} },
                        "400": { "description": "Invalid output supplied", "content": {} }
                    },
                    "security": [
                        { "api_key": [] }
                    ]
                }
            }
        },
    }
})

Profile
Max van Kampen
CEO, Founder, Alicon, Aliconnect
[email protected]

⚠️ **GitHub.com Fallback** ⚠️