# API # API v2.0 Version 2.0 of the sygnalAPI, a websocket and HTTP API for control and feed back for all of the sygnal equipment # Websocket Connections The Sygnal API is primarily websocket based. You can establish a connection to a sygnal device via the configured IP and port of the webGUI. By the nature of being a websocket API there is no direct request-response model. However, in most cases when sending a request you should expect a single response. This response may be just to you, or to all clients if your request caused a change other clients are subscribed to recieveing events about. For example, if you send a requet to start a stream, this will then start the stream and then send an update to ALL connected API clients with the new state of the stream. In most cases when creating, updating or deleting an item this change will be sent to all clients that are subscribed, it will in most cases send an updated list of all items to give clients an opertunity to recover if there has been de-sync. For example, if you create a new stream, a list of all streams including the new one will be sent to all clients. The general stuctures of the Sygnal applications are split into 'modules'. For example the teleprompter is it's own module and all communication about it are flagged as part of the 'promp' module. When opening a new API connection, you must 'register' as part of this you specify the modules you would like to send/recieve messages from. This means you could write a plugin/extension for playback and not recieve the unecessary prompt messages. You could also use this as a way of seperating out your communication or even multithreading workflows. There is no limit to subscribers to each module or to the origin of the subscribers. Meaning you could open 3 different prompt API connections, all 3 would receive all the prompt messages, but each one could be responsible for sending a different type of message. There is a defined strcuture and methodology to the websocket and HTTP message structure outlined in the message structure section. # HTTP Connections The HTTP API follows the same format as the websocket API, in fact it used the same handler internally! All requests should be sent as POST requests and the message should be sent JSON encoded as the body of the request. # Message Structure The websocket and HTTP messages/requests have a defined structure that must be followed when both sending and recieving a message from a unit/server. A message has two components, a header with some meta data and the payload, with the contents of the message. All keys in this structure are camelcase. ### Header \[object\] The header of the message contains 7 fields as follows:
**Field** **Type** **Structure** **Purpose** **Example**
fromID string First letter of 'type' \_ 'timestamp of device initialisation' \_ version the ID of the origional sender of the message S\_1707151018347\_1.0.9
timestamp number unixtimestamp The millisecond unix timestamp of when the message was sent 1707160733725
version string version.major.minor Semantic version of the API version in use 1.0.9
type string Capitalised string The type of the sender, to help identify what the prupose of the device is Server/Browser
active boolean true/false To determine if the origonal sending device is still online on the network. The message could be a relayed then cached message true/false
messageID number unixtimestamp The ID of the origional message, this is typically the unixtimestamp at the time of sending, but could be any number. For detecting message duplication 1707160733725
### Payload \[object\] The structure of the payload is less set as there are options based on usage. ##### Module \[string\] There will always be a 'module' field in all messages except the register message, as the regsiter message is unique. The module field is used to determine what module the message is from/for. This field is a string Current valid options are: prompt, playback, system, config, network ##### Command \[string\] Like module, there will always be a command field, event regsiter has the command field! The contains the actual 'command' you are sending to the module, e.g. set, update, delete e.t.c. ##### Data \[object/any\] In most cases there will be a 'data' property which contains the actual data. In many case this is a series of key value pairs, however, in some cases that can be a large complex object and in others simply just a long string. ### Register To register you send a message the typical header strcuture and payload with the command "register" and a payload block which should be an object containing modules names you wish to send and recieve messages from with the value true for recieve and false to ignore. As folows: ```JSON { "header": { "fromID": "B_1707160733672_0.1.9", "timestamp": 1707160733738, "version": "0.1.9", "type": "Browser", "system": "SygnalEnc-XXXX", "active": true, "messageID": 1707160733738 }, "payload": { "module": "core", "command": "register", "data": { "flows":true, "network":true, "system":false, "prompt":true } } } ``` ### Ping/Pong There is a background ping/pong every second run by the server to all it's attached clients. This should be responded to or your client will be marked as inactive and you will stop recieving messages. If this occurs, sending a new message should re-activate your connection. If you are inactive for too long your connection will be closed by the server. A ping message will contain a single command with the value "ping", it should be responded to with a single command "pong" as seen bellow: ```json { "header": { "fromID": "S_1707151018347_0.1.9", "timestamp": 1707160734618, "version": "0.1.9", "type": "Server", "active": true, "messageID": 1707160734618, }, "payload": { "command": "ping" } } ``` ### Examples: Setting the system name ```json { "header":{ "fromID":"S_1707151018347_1.0.9", "timestamp":1707160733725, "version":"1.0.9", "type":"Server", "active":true, "messageID":1707160733725, }, "payload":{ "module":"system", "command":"config", "data": { "key":"systemName", "value":"SygnalEnc-XXXX" } } } ``` Recieveing a flow ```JSON { "header": { "fromID": "S_1707151018347_0.1.9", "timestamp": 1707160734618, "version": "0.1.9", "type": "Server", "active": true, "messageID": 1707160734618, }, "payload": { "module": "flows", "command": "status", "data": { "name": "Hardware Encoder #1", "ID": "800fcb9b-7627-42be-b447-30c137a828ef", "type": "Hardware-Encoder", "flowType": "ENCODE", "profile": { "codec": "h265", "profile": "66", "bps": "", "bpsMin": "", "bpsMax": "", "gop": "", "rcMode": "0", "rotation": "0", "qpInit": "26", "qpMax": "0", "qpMin": "0", "qpStep": "-1" }, "enabled": false, "active": false, "caps": {}, "debug": false } } } ``` Ping ```json { "header": { "fromID": "S_1707151018347_0.1.9", "timestamp": 1707160734618, "version": "0.1.9", "type": "Server", "active": true, "messageID": 1707160734618, }, "payload": { "command": "ping" } } ``` Recieving the current network interface info ```JSON { "header": { "fromID": "S_1707151018347_0.1.9", "timestamp": 1707160733723, "version": "0.1.9", "type": "Server", "active": true, "messageID": 1707160733723, }, "payload": { "module": "network", "command": "ifaces", "data": [ { "ifindex": 1, "ifname": "lo", "flags": [ "LOOPBACK", "UP", "LOWER_UP" ], "mtu": 65536, "qdisc": "noqueue", "operstate": "UNKNOWN", "group": "default", "txqlen": 1000, "link_type": "loopback", "address": "00:00:00:00:00:00", "broadcast": "00:00:00:00:00:00", "addr_info": [ { "family": "inet", "local": "127.0.0.1", "prefixlen": 8, "scope": "host", "label": "lo", "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "::1", "prefixlen": 128, "scope": "host", "valid_life_time": 4294967295, "preferred_life_time": 4294967295 } ] }, { "ifindex": 2, "ifname": "enP2p33s0", "flags": [ "BROADCAST", "MULTICAST", "UP", "LOWER_UP" ], "mtu": 1500, "qdisc": "mq", "operstate": "UP", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "7a:b2:4e:29:01:79", "broadcast": "ff:ff:ff:ff:ff:ff", "permaddr": "3e:9f:56:b0:fe:c0", "addr_info": [ { "family": "inet", "local": "192.168.1.29", "prefixlen": 24, "broadcast": "192.168.1.255", "scope": "global", "dynamic": true, "noprefixroute": true, "label": "enP2p33s0", "valid_life_time": 2775, "preferred_life_time": 2775 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210:3f:39e3:590c:a04b", "prefixlen": 64, "scope": "global", "temporary": true, "dynamic": true, "valid_life_time": 1194, "preferred_life_time": 594 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210:bbab:1a3:272a:8c49", "prefixlen": 64, "scope": "global", "dynamic": true, "mngtmpaddr": true, "noprefixroute": true, "valid_life_time": 1194, "preferred_life_time": 594 }, { "family": "inet6", "local": "fdb4:be22:9e07:10::f5b", "prefixlen": 128, "scope": "global", "dadfailed": true, "tentative": true, "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "fdb4:be22:9e07:10:cb85:5d3d:4f:f4ac", "prefixlen": 64, "scope": "global", "temporary": true, "dynamic": true, "valid_life_time": 600378, "preferred_life_time": 81483 }, { "family": "inet6", "local": "fdb4:be22:9e07:10:d098:9a1e:6396:72be", "prefixlen": 64, "scope": "global", "mngtmpaddr": true, "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "fe80::4408:7058:8fe9:54f9", "prefixlen": 64, "scope": "link", "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 } ], "gateway": "192.168.1.1" }, { "ifindex": 3, "ifname": "enP4p65s0", "flags": [ "BROADCAST", "MULTICAST", "UP", "LOWER_UP" ], "mtu": 1500, "qdisc": "mq", "operstate": "UP", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "46:62:0d:1d:e2:5b", "broadcast": "ff:ff:ff:ff:ff:ff", "permaddr": "aa:04:f5:fd:4e:35", "addr_info": [ { "family": "inet", "local": "192.168.88.223", "prefixlen": 24, "broadcast": "192.168.88.255", "scope": "global", "dynamic": true, "noprefixroute": true, "label": "enP4p65s0", "valid_life_time": 419, "preferred_life_time": 419 }, { "family": "inet6", "local": "fe80::51d7:4511:97ea:b968", "prefixlen": 64, "scope": "link", "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 } ], "gateway": "192.168.88.1" }, { "ifindex": 4, "ifname": "wlP3p49s0", "flags": [ "BROADCAST", "MULTICAST", "UP", "LOWER_UP" ], "mtu": 1500, "qdisc": "noqueue", "operstate": "UP", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "a0:02:a5:bd:d4:36", "broadcast": "ff:ff:ff:ff:ff:ff", "addr_info": [ { "family": "inet", "local": "192.168.1.39", "prefixlen": 24, "broadcast": "192.168.1.255", "scope": "global", "dynamic": true, "noprefixroute": true, "label": "wlP3p49s0", "valid_life_time": 3373, "preferred_life_time": 3373 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210::f5b", "prefixlen": 128, "scope": "global", "dynamic": true, "noprefixroute": true, "valid_life_time": 994, "preferred_life_time": 394 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210:996e:cd23:3952:2114", "prefixlen": 64, "scope": "global", "temporary": true, "dynamic": true, "valid_life_time": 1194, "preferred_life_time": 594 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210:3f13:80eb:c42b:56d3", "prefixlen": 64, "scope": "global", "dynamic": true, "mngtmpaddr": true, "noprefixroute": true, "valid_life_time": 1194, "preferred_life_time": 594 }, { "family": "inet6", "local": "fdb4:be22:9e07:10::f5b", "prefixlen": 128, "scope": "global", "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "fdb4:be22:9e07:10:9cd6:5d24:63b6:896a", "prefixlen": 64, "scope": "global", "temporary": true, "dynamic": true, "valid_life_time": 600319, "preferred_life_time": 81343 }, { "family": "inet6", "local": "fdb4:be22:9e07:10:90c1:4b8f:4d19:68e0", "prefixlen": 64, "scope": "global", "mngtmpaddr": true, "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "fe80::a750:aedd:b0d8:d2c2", "prefixlen": 64, "scope": "link", "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 } ], "gateway": "192.168.1.1" } ] } } ``` # JavaScript Wrapper Library There is a JavaScript ES6 wrapper library that can be imported and contains a class that can be used to simplify the communication. For access this reach out on ### Class Constructor `serverURL, type, clientVersion, currentSystem, ssl = false, logger = console` ### Methods setSystem(string) close() send(object) makeHeader(): object connect(string) ### Events open close error: error message: header, payload, event disconnect ping ### Examples An example of the libary being imported and used when it is in the /modles/ subdirectory is as follows: ```javascript import _ServerSocket from './modules/serverSocket.js'; const serverURL = '127.0.0.1'; const APIVersion = '1.0.0'; const systemName = 'Demo'; const isSSL = false; const type = 'Browser'; const Server = new _ServerSocket(serverURL, type, APIVersion, systemName, isSSL); Server.addEventListener('message', event => { const [header, payload] = event.detail; socketDoMessage(header, payload); }); Server.addEventListener('open', event => { Server.send({ 'command':'register', 'subscribe': ['flows', 'network', 'system', 'prompt'] }); document.getElementById('disconnected').classList.add('hidden'); }); Server.addEventListener('close', ()=>{ const _logs = document.getElementById('logs'); _logs.innerHTML = '
Disconnected
' + _logs.innerHTML; document.getElementById('disconnected').classList.remove('hidden') }); function socketDoMessage(header, payload) { switch (payload.module) { case 'flows': doFlows(payload); break; case 'network': doNetwork(payload); break; case 'prompt': doPropmt(payload); break; case 'playback': doPlayback(payload); break; case 'system': doSystem(payload); break; default: break; } } function doFlows(payload) { //doStuff } function doNetwork(payload) { //doStuff } function doPropmt(payload) { //doStuff } function doPlayback(payload) { //doStuff } function doSystem(payload) { //doStuff } ``` # Modules ### Core \[core\]
core - requests The core module is only really used to register your connection
**Command** **Data** **Description**
register object: {module:bool} Used to register your connection and recieve messages from the specified modules
ping -
pong \-
### System Information \[sysInfo\]
sysInfo - requests The system infromation module can be used to retrieve information about the device, it's IO and current status, including temperatures
**Command** **Data** **Description**
io - Retrieves the list of IO and details about that IO
info - Retrieves the board info from the device
rate int {time - ms} Sets the polling rate for the system info watcher
magewellInfo - Returns info about the specified SDI source
### api ### system ### gpio ### joystick ### ina219 ### licence ### gstreamer ### flows ### # API v1.0 Version 1.0 of the sygnalAPI, a websocket API for control and feed back for all of the sygnal equipment # HTTP Connections There are a limited number of HTTP endpoints that can be used for some specific purposes as detailed bellow. These are intended for mechanical purposes and are not generally considered 'safe to use' and could be subject to change without a deprecation notice or an API version change. Use at your own risk! ### Public #### GET /ident This will trigger this ident feature, making the GUI and buttons flash on a unit. ### Authenticated To access these endpoints the user must be authenticated and have a valid HTTP only session cookie. #### GET /flows This returns a JSON object of all configured flows. #### GET /downloadLogs This returns a .zip file of ALL logs on the unit/server. #### GET /licenseMake This will create a license if the required parameters are populated with valid credentials. To gain access to this endpoint please contact to discuss a comercial agreement to fit your workflow. #### POST /licenseUpload This can be used to upload a license file to apply to the unit. # Websocket Connections The Sygnal API is websocket based. You can establish a connection to a sygnal device via the configured IP and port of the webGUI. By the nature of being a websocket API there us no direct request-response model. However, in most cases when sending a request you should expect a single response. For example, if you send a requet to start a stream, this will then start the stream and then send an update to ALL connected API clients with the new state of the stream. In most cases when creating, updating or deleting an item this change will be sent to all clients that are subscribed, it will in most cases send an updated list of all items to give clients an opertunity to recover if there has been de-sync. For example, if you create a new stream, a list of all streams including the new one will be sent to all clients. The general stuctures of the Sygnal applications are split into 'modules'. For example the teleprompter is it's own module and all communication about it are flagged as part of the 'promp' module. When opening a new API connection, you must 'register' as part of this you specify the modules you would like to send/recieve messages from. This means you could write a plugin/extension for playback and not recieve the unecessary prompt messages. You could also use this as a way of seperating out yur communication or even multithreading workflows. There is no limit to subscribers to each module or to the origin of the subscribers. Meaning you could open 3 different prompt API connections, all 3 would receive all the prompt messages, but each one could be responsible for sending a different type of message. There is a defined strcuture and methodology to the websocket message structure outlined in the next section. # Websocket Structure The websocket messages have a defined structure that must be followed when both sending and recieving a message from a unit/server. A message has two components, a header with some meta data and the payload, with the contents of the message. All keys in this structure are camelcase. ### Header \[object\] The header of the message contains 7 fields as follows:
**Field** **Type** **Structure** **Purpose** **Example**
fromID string First letter of 'type' \_ 'timestamp of device initialisation' \_ version the ID of the origional sender of the message S\_1707151018347\_1.0.9
timestamp number unixtimestamp The millisecond unix timestamp of when the message was sent 1707160733725
version string version.major.minor Semantic version of the API version in use 1.0.9
type string Capitalised string The type of the sender, to help identify what the prupose of the device is Server/Browser
active boolean true/false To determine if the origonal sending device is still online on the network. The message could be a relayed then cached message true/false
messageID number unixtimestamp The ID of the origional message, this is typically the unixtimestamp at the time of sending, but could be any number. For detecting message duplication 1707160733725
recipients array \[fromID, fromID\] An array of IDs that have been confirmed to have received this message. This is used in mesh networks to ensure messages don't get stuck in loops. Can also be used to track the path of a message through the network \[S\_1707184718392\_1.0.9, B\_1707174713595\_1.0.8\]
### Payload \[object\] The structure of the payload is less set as there are options based on usage. ##### Module \[string\] There will always be a 'module' field in all messages except the register message, as the regsiter message is unique. The module field is used to determine what module the message is from/for. This field is a string Current valid options are: prompt, playback, system, config, network ##### Command \[string\] Like module, there will always be a command field, event regsiter has the command field! The contains the actual 'command' you are sending to the module, e.g. set, update, delete e.t.c. ##### Key/Value \[string/any\] When the data you are sending is of the form of a signle key/value pair, you can specify a 'key' and a 'value' field and put your values in as a key \[string\] and value \[any\]. Generally it is prefered to use the 'data' field instead. ##### Data \[object/any\] In most cases there will be a 'data' property which contains the actual data. In many case this is a series of key value pairs, however, in some cases that can be a large complex object and in others simply just a long string. ### Register To register you send a message the typical header strcuture and payload with the command "register" and a special payload block "subscribe" which should be an array containing modules names you wish to send and recieve messages from. As folows: ```JSON { "header": { "fromID": "B_1707160733672_0.1.9", "timestamp": 1707160733738, "version": "0.1.9", "type": "Browser", "system": "SygnalEnc-XXXX", "active": true, "messageID": 1707160733738 }, "payload": { "command": "register", "subscribe": [ "flows", "network", "system", "prompt" ] } } ``` ### Ping/Pong There is a background ping/pong every second run by the server to all it's attached clients. This should be responded to or your client will be marked as inactive and you will stop recieving messages. If this occurs, sending a new message should re-activate your connection. If you are inactive for too long your connection will be closed by the server. A ping message will contain a single command with the value "ping", it should be responded to with a single command "pong" as seen bellow: ```json { "header": { "fromID": "S_1707151018347_0.1.9", "timestamp": 1707160734618, "version": "0.1.9", "type": "Server", "active": true, "messageID": 1707160734618, "recipients": [] }, "payload": { "command": "ping" } } ``` ### Examples: Setting the system name ```json { "header":{ "fromID":"S_1707151018347_1.0.9", "timestamp":1707160733725, "version":"1.0.9", "type":"Server", "active":true, "messageID":1707160733725, "recipients":[] }, "payload":{ "module":"system", "command":"config", "key":"systemName", "value":"SygnalEnc-XXXX" } } ``` Recieveing a flow ```JSON { "header": { "fromID": "S_1707151018347_0.1.9", "timestamp": 1707160734618, "version": "0.1.9", "type": "Server", "active": true, "messageID": 1707160734618, "recipients": [] }, "payload": { "module": "flows", "command": "status", "data": { "name": "Hardware Encoder #1", "ID": "800fcb9b-7627-42be-b447-30c137a828ef", "type": "Hardware-Encoder", "flowType": "ENCODE", "profile": { "codec": "h265", "profile": "66", "bps": "", "bpsMin": "", "bpsMax": "", "gop": "", "rcMode": "0", "rotation": "0", "qpInit": "26", "qpMax": "0", "qpMin": "0", "qpStep": "-1" }, "enabled": false, "active": false, "caps": {}, "debug": false } } } ``` Ping ```json { "header": { "fromID": "S_1707151018347_0.1.9", "timestamp": 1707160734618, "version": "0.1.9", "type": "Server", "active": true, "messageID": 1707160734618, "recipients": [] }, "payload": { "command": "ping" } } ``` Recieving the current network interface info ```JSON { "header": { "fromID": "S_1707151018347_0.1.9", "timestamp": 1707160733723, "version": "0.1.9", "type": "Server", "active": true, "messageID": 1707160733723, "recipients": [] }, "payload": { "module": "network", "command": "ifaces", "data": [ { "ifindex": 1, "ifname": "lo", "flags": [ "LOOPBACK", "UP", "LOWER_UP" ], "mtu": 65536, "qdisc": "noqueue", "operstate": "UNKNOWN", "group": "default", "txqlen": 1000, "link_type": "loopback", "address": "00:00:00:00:00:00", "broadcast": "00:00:00:00:00:00", "addr_info": [ { "family": "inet", "local": "127.0.0.1", "prefixlen": 8, "scope": "host", "label": "lo", "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "::1", "prefixlen": 128, "scope": "host", "valid_life_time": 4294967295, "preferred_life_time": 4294967295 } ] }, { "ifindex": 2, "ifname": "enP2p33s0", "flags": [ "BROADCAST", "MULTICAST", "UP", "LOWER_UP" ], "mtu": 1500, "qdisc": "mq", "operstate": "UP", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "7a:b2:4e:29:01:79", "broadcast": "ff:ff:ff:ff:ff:ff", "permaddr": "3e:9f:56:b0:fe:c0", "addr_info": [ { "family": "inet", "local": "192.168.1.29", "prefixlen": 24, "broadcast": "192.168.1.255", "scope": "global", "dynamic": true, "noprefixroute": true, "label": "enP2p33s0", "valid_life_time": 2775, "preferred_life_time": 2775 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210:3f:39e3:590c:a04b", "prefixlen": 64, "scope": "global", "temporary": true, "dynamic": true, "valid_life_time": 1194, "preferred_life_time": 594 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210:bbab:1a3:272a:8c49", "prefixlen": 64, "scope": "global", "dynamic": true, "mngtmpaddr": true, "noprefixroute": true, "valid_life_time": 1194, "preferred_life_time": 594 }, { "family": "inet6", "local": "fdb4:be22:9e07:10::f5b", "prefixlen": 128, "scope": "global", "dadfailed": true, "tentative": true, "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "fdb4:be22:9e07:10:cb85:5d3d:4f:f4ac", "prefixlen": 64, "scope": "global", "temporary": true, "dynamic": true, "valid_life_time": 600378, "preferred_life_time": 81483 }, { "family": "inet6", "local": "fdb4:be22:9e07:10:d098:9a1e:6396:72be", "prefixlen": 64, "scope": "global", "mngtmpaddr": true, "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "fe80::4408:7058:8fe9:54f9", "prefixlen": 64, "scope": "link", "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 } ], "gateway": "192.168.1.1" }, { "ifindex": 3, "ifname": "enP4p65s0", "flags": [ "BROADCAST", "MULTICAST", "UP", "LOWER_UP" ], "mtu": 1500, "qdisc": "mq", "operstate": "UP", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "46:62:0d:1d:e2:5b", "broadcast": "ff:ff:ff:ff:ff:ff", "permaddr": "aa:04:f5:fd:4e:35", "addr_info": [ { "family": "inet", "local": "192.168.88.223", "prefixlen": 24, "broadcast": "192.168.88.255", "scope": "global", "dynamic": true, "noprefixroute": true, "label": "enP4p65s0", "valid_life_time": 419, "preferred_life_time": 419 }, { "family": "inet6", "local": "fe80::51d7:4511:97ea:b968", "prefixlen": 64, "scope": "link", "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 } ], "gateway": "192.168.88.1" }, { "ifindex": 4, "ifname": "wlP3p49s0", "flags": [ "BROADCAST", "MULTICAST", "UP", "LOWER_UP" ], "mtu": 1500, "qdisc": "noqueue", "operstate": "UP", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "a0:02:a5:bd:d4:36", "broadcast": "ff:ff:ff:ff:ff:ff", "addr_info": [ { "family": "inet", "local": "192.168.1.39", "prefixlen": 24, "broadcast": "192.168.1.255", "scope": "global", "dynamic": true, "noprefixroute": true, "label": "wlP3p49s0", "valid_life_time": 3373, "preferred_life_time": 3373 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210::f5b", "prefixlen": 128, "scope": "global", "dynamic": true, "noprefixroute": true, "valid_life_time": 994, "preferred_life_time": 394 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210:996e:cd23:3952:2114", "prefixlen": 64, "scope": "global", "temporary": true, "dynamic": true, "valid_life_time": 1194, "preferred_life_time": 594 }, { "family": "inet6", "local": "2a0d:3344:1d6:9210:3f13:80eb:c42b:56d3", "prefixlen": 64, "scope": "global", "dynamic": true, "mngtmpaddr": true, "noprefixroute": true, "valid_life_time": 1194, "preferred_life_time": 594 }, { "family": "inet6", "local": "fdb4:be22:9e07:10::f5b", "prefixlen": 128, "scope": "global", "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "fdb4:be22:9e07:10:9cd6:5d24:63b6:896a", "prefixlen": 64, "scope": "global", "temporary": true, "dynamic": true, "valid_life_time": 600319, "preferred_life_time": 81343 }, { "family": "inet6", "local": "fdb4:be22:9e07:10:90c1:4b8f:4d19:68e0", "prefixlen": 64, "scope": "global", "mngtmpaddr": true, "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 }, { "family": "inet6", "local": "fe80::a750:aedd:b0d8:d2c2", "prefixlen": 64, "scope": "link", "noprefixroute": true, "valid_life_time": 4294967295, "preferred_life_time": 4294967295 } ], "gateway": "192.168.1.1" } ] } } ``` # JavaScript Wrapper Library There is a JavaScript ES6 wrapper library that can be imported and contains a class that can be used to simplify the communication. For access this reach out on ### Class Constructor `serverURL, type, clientVersion, currentSystem, ssl = false, logger = console` ### Methods setSystem(string) close() send(object) makeHeader(): object connect(string) ### Events open close error: error message: header, payload, event disconnect ping ### Examples An example of the libary being imported and used when it is in the /modles/ subdirectory is as follows: ```javascript import _ServerSocket from './modules/serverSocket.js'; const serverURL = '127.0.0.1'; const APIVersion = '1.0.0'; const systemName = 'Demo'; const isSSL = false; const type = 'Browser'; const Server = new _ServerSocket(serverURL, type, APIVersion, systemName, isSSL); Server.addEventListener('message', event => { const [header, payload] = event.detail; socketDoMessage(header, payload); }); Server.addEventListener('open', event => { Server.send({ 'command':'register', 'subscribe': ['flows', 'network', 'system', 'prompt'] }); document.getElementById('disconnected').classList.add('hidden'); }); Server.addEventListener('close', ()=>{ const _logs = document.getElementById('logs'); _logs.innerHTML = '
Disconnected
' + _logs.innerHTML; document.getElementById('disconnected').classList.remove('hidden') }); function socketDoMessage(header, payload) { switch (payload.module) { case 'flows': doFlows(payload); break; case 'network': doNetwork(payload); break; case 'prompt': doPropmt(payload); break; case 'playback': doPlayback(payload); break; case 'system': doSystem(payload); break; default: break; } } function doFlows(payload) { //doStuff } function doNetwork(payload) { //doStuff } function doPropmt(payload) { //doStuff } function doPlayback(payload) { //doStuff } function doSystem(payload) { //doStuff } ```