App Development Guide

Basics

The HTML rendering backend enables developers to use regular HTML5 with CSS and JavaScript and prepare web applications formatted with device specifications in mind (size of display, speed of display refresh), just as they would prepare a web application intended for use on any mobile device.

Note

The HTML rendering backend was formerly known as Okular.

The Visionect Software Suite does not pose any special requirements on the use of specific back-end, technology so developers are free to use their own favorite programming environment to prepare complex web applications.

../_images/okular_render_path.png

The HTML rendering backend provides a WebKit-based web browser session for each device, which means:

  • A web application (web page) is made available on the client by configuring the target application URL using the Management Interface.
  • Application testing can be done in a regular desktop browser (WebKit-based - Apple Safari, Google Chrome, Epiphany - for best results). The application should act exactly the same in the browser as it does on the device. Any discrepancies should be reported as bugs.
  • Developers can access device specific functions via Visionect JavaScript extensions that are provided by the HTML rendering backend.

Web page rendering

When the HTML rendering backend creates a new WebKit session for a group of clients (often there is just one client), the WebKit session loads the URL as determined by the Software Suite cconfiguration. The backend will render the viewport of the session window and transmit new image(s) to the clients in two cases:

  1. The HTML rendering backend detects a change in the session viewport. After the change it waits for RenderTimeout, before actually rendering. Until this timeout occurs, the application has an opportunity to use JavaScript Extensions to force limit rendering to specified regions only and in this way optimize rendering performance. If the application fails to do so in the time allotted then a full viewport will be rendered. Check also Rendering performance and optimizations.
  2. The web application requests a full viewport (full screen) rendering by using Visionect JavaScript extensions.

Supported web technologies

The HTML rendering backend supports:

  • Broad HTML5 functionality
  • JavaScript with full AJAX support
  • Full CSS3 (ACID3 test compliant)

Warning

Default browser UI constructs based on the desktop environment (such as scroll bars and drop down lists) are currently unsupported. To cope with this issue there are a number of JavaScript plug-ins which remove the default and replace them with HTML, CSS and JavaScript implementation.

E-paper modes of operation

E-paper screens have different modes of operation, making it possible to choose different display bit-depths which impact the screen performance:

  • 4-bit grayscale, which causes the device screen to refresh in ~750 msec
  • 1-bit black and white, which causes the device screen to refresh in ~250 msec
  • 1-bit A2 waveform, which refreshes a region in ~125 msec

Warning

This section applies to the first generation of the Visionect Sign 6”.

Warning

The values provided are those necessary for the EPSON controller to push the image. Many other factors impact the rendering time, among them the connectivity type, RSSI, data size, display size and resolution.

Regardless of the mode chosen, it is possible to request an invert of the currently displayed image prior to new image draw. This is especially important in 1-bit B&W mode, as every display draw leaves traces of the previous image shown behind (the ‘ghosting’ effect). The client devices come with a default Software Suite setting to do an invert for every full screen refresh.

Partial screen updating is supported on most devices, but might not work on some firmware versions. You can implement it using the the render rectangles function: function okular.RenderRectangles(rectanglesArray) or using the JavaScript rendering library. If you encounter any problems, you should check the following:

  • The Visionect Software Suite version: upgrade your Software Suite to the latest version. You can do it by running the following commands.
docker pull visionect/server
docker stop vserver
docker rm vserver
docker run  --privileged --cap-add=MKNOD --cap-add SYS_ADMIN --device /dev/fuse  -d --restart=always -p 8081:8081 -p 11112:11112 -p 11113:11113 --link vserver_postgres:db2_1   --volumes-from vdata --name vserver visionect/server
  • Force Rectangle Support: open the Management Interface and check if the Force Rectangle Support setting (Settings -> Default Device Settings) is enabled.
  • Encoding: make sure you don’t mix 1-bit and 4-bit encoding in the same image packet, as this can cause problems with updating content and might result in a full screen refresh.

Graphics dithering

Since web pages usually come with graphical data prepared in colors, Visionect’s Graphics Engine uses one of the methods of dithering to convert color into the required bit-depth for electronic paper displays. The currently supported methods of dithering are:
  • Floyd-Steinberg
  • Bayer

The dithering type is configured by the HTML rendering backend configuration or directly with JavaScript.

Fonts

The Visionect Software Suite comes with a set of default fonts, but it is possible to add your own, just like on other web pages.

If you call a font that the browser does not recognize, this could lead to visible differences in font interpretation between different web browsers, as well as the HTML renderer of the Visionect Software Suite. To ensure consistency through all browsers and Visionect Software Suite, it is recommended to import the font in your application. In this way yout will not be dependent on the Suite itself and will avoid any troubles if later migrating to another server. You can use the standard Web Fonts using @font-face CSS rule - see more details at: http://www.w3schools.com/cssref/css3_pr_font-face_rule.asp and http://www.fontsquirrel.com/tools/webfont-generator.

HTTP Proxy

WebKit engine will use the HTTP proxy, if the http_proxy environment variable is set. Exceptions can be set in the comma separated list inside the no_proxy environment variable.

export http_proxy=http://10.203.0.1:5187/
export no_proxy="localhost,127.0.0.1,localaddress,.localdomain.com"

To run the engine with those variables, it is recommend, to set them in docker run -e options when creating the docker container.

docker run -e http_proxy="http://182.253.123.81:8080/" --privileged --cap-add=MKNOD --cap-add SYS_ADMIN --device /dev/fuse -d --restart=always -p 8081:8081 -p 11112:11112 -p 11113:11113 --link vserver_postgres:db2_1 --volumes-from vdata --name vserver visionect/visionect-server-v3

Docker-less deployments can use the supervisor engine start script okular.conf to add the same variables.


JavaScript Rendering Library

We provide a JavaScript library intended to ease the development of applications by providing wrappers for faster and easier graphics rendering on Visionect client devices. Koalalib library can be downloaded from GitHub (https://github.com/visionect/koalalib).

To get control over rendering you need to:

  1. Add the library to your document.
<script src="jquery.js"></script>
<script src="okular.js"></script>
  1. Call .tmList(); function on elements which you want to push to screen.
//JavaScript code
//I want to push a popup screen (implemented as a "div" element with class .popup) to render after I touch a button.

function showPopup(text){
 $(".popup").text(text).show().tmList();
}

function closePopup(){
 $(".popup").text("").tmList().hide();
}

$(".button").click(function(){
    showPopup("Popup is shown");
});

$(".popup").click(function(){
    hidePopup("Popup is shown");
});

More documentation is available on GitHub. The use of this library is strongly advised, as it prevents the typical errors with direct access to Visionect JavaScript Extensions.


JavaScript Rendering Extensions

Rendering support

function okular.RenderImage()

Renders the complete viewport and sends it to device(s) display(s).

function okular.RenderRectangles(rectanglesArray)

var rectanglesArray = [{x: integer, y: integer, width: integer[, encoding: integer] [, dithering: integer]
[, rectangleUpdateOptions: integer][, rectangleOptions: integer]}, ...]

Limits the rendering of the next viewport change to specified rectangle regions only. After a change, the HTML rendering backend will wait for a short period before rendering. We have a limited amount of time before rendering to provide those regions, otherwise the full screen view will be rendered. (For details see Display options, rendering and ghosting).

This function is different from okular.RenderImage(). Firstly, it does not trigger rendering by itself and secondly, the function accepts rectangle information.

The information about the rectangles we want to dissect and display is provided with the argument list of the function call, together with some other options, such as the bit-depth that is to be used.

Be careful not to overlay various rectangles as this will slow down the screen refresh.

For the possible encoding and dithering options check okular.Setup()

  • Encoding - any value from below, or undefined if we want to keep the old value. The JavaScript API generally accepts the encoding values 1, 4 and 0. Display images may be encoded using 1 bit or with 4 bits per pixel. The value 0 means you are using the default session encoding.
okular.EncodingDefault = 0;
okular.Encoding1Bit    = 1;
okular.Encoding4bit    = 4;
  • Dithering (optional) - any value from below, or undefined if we want to keep the old value. For better image quality, the Visionect Software Suite supports the following device display images dithering options and constants:
okular.DitheringDefault = 0; // Use session default dithering.
okular.DitheringNone = 1; //Do not use dithering at all.
okular.DitheringBayer = 2; // Use Bayer dithering.
okular.DitheringFloydSteinberg = 3; // Use Floyd-Steinberg dithering.
  • rectangleUpdateOptions (optional) - rectangle image options, or undefined if we want to keep the old value. This is a 16 bit value, where the byte with the higher weight sets up the display update type (region, full, ...), and the second byte selects the display drawing waveform (some waveforms work only with certain encodings). The options are:
//update mode: Select which update mode should be used. Following update modes are available:
    okular.RectangleUpdateFull          = 0x0000;
    okular.RectangleUpdateFullArea      = 0x0100;
    okular.RectangleUpdateFullArea      = 0x0200;
    okular.RectangleUpdatePart          = 0x0300;
    okular.RectangleUpdatePartArea      = 0x0400;
//waveform_mode: Select which waveform mode should be used by display. Following waveform modes are available:
    okular.RectangleUpdateWaveformINIT  = 0x0000;
    okular.RectangleUpdateWaveformDU    = 0x0001;
    okular.RectangleUpdateWaveformGC16  = 0x0002;
    okular.RectangleUpdateWaveformGC4   = 0x0003;
    okular.RectangleUpdateWaveformA2    = 0x0004;
Update type rectangleUpdateOption
FULL SCREEN 2
FULL AREA 258
PART SCREEN 514
PART AREA 770

Warning

Because of the technical characteristics of electronic paper technology it is strongly recommended to use the fullscreen update approximately after every 10th image change.

Note

The use of waveform and update method is display-specific. Contact our support for additional information and the correct use.

  • rectangleOptions (optional) - extra rectangle options, or undefined if we want to keep the old value.
okular.RectangleEnableTransperency = 0x1; // Enable transparency for current image
okular.RectangleDisableInverse     = 0x2; // Disable image inverse
  • imageUpdateOptions (optional) - rectangle image container options, or undefined if we want to keep the old value. You should set this only if you really know what you are doing.
okular.ImageUpdateClearScreen  = 0x01; // Clean screen before update
okular.ImageUpdateBorderUpdate = 0x02; // Enable border update on displays which supports this feature. The color bit specifies the border color
okular.ImageUpdateBorderWhite  = 0x04; // If border update is enabled. This sets white color of the border, otherwise it's black

Example 1

okular.RenderRectangles([{x:400, y:0, width: 200, height: 300, encoding: 1, dithering: okular.DitheringBayer}, {x:0, y:0, width: 200, height: 300, encoding: 1, dithering: okular.DitheringDefault}]);

Warning

You should not mix 1-bit and 4-bit encoding in the same image packet, as this can cause problems with updating content and could result in a fullscreen refresh. Also, make sure that the “Force Rectangle Support” setting in the Management Interface (Settings -> Default Device Settings) is enabled.

Example 2

//uses jQuery library.
//render a popup
var my_popup = $("#mypopup"); //get the div you want to render
var my_popup2 = $("#mypopup2"); //get the second div you want to render

list = new Array(); //create a list for rectangles

//first rectangle
list.push({x: my_popup.offset().left, y: my_popup.offset().top,
   width: my_popup.outerWidth(), height: my_popup.outerHeight(), encoding: 1, dithering: okular.DitheringDefault});

//second rectangle
list.push({x: my_popup2.offset.left, y: my_popup2.offset().top,
    width: my_popup2.outerWidth(), height: my_popup2.outerHeight(), encoding: 4, dithering: okular.DitheringNone});

 okular.RenderRectangles(list);

function okular.Setup(encoding, dithering, rectangleUpdateOptions,rectangleOptions, imageUpdateOptions)

Sets the global default settings for all subsequent screen renders for the current session. The settings will trump the default settings set by Management Interface. For more details see server configuration.

Warning

Some of the rendering-related settings might not work correctly on first generation Visionect Signs or if your client device is running on an older version of Visionect firmware. Please contact our support for more details.

Example:

okular.Setup(okular.Encoding1Bit, okular.DitheringBayer);
okular.Setup(okular.Encoding4Bit, undefined, undefined, undefined, okular.ImageUpdateBorderUpdate );

A working example of rendering rectangles can be found at Okular_API_example.zip.

Rendering performance and optimizations

The Visionect Software Suite should be able to answer a client device request approximately in hundredth of a millisecond. In order to enable the best Software Suite performance, you should make sure that:

  • your web application is responsive enough (which includes all possible back-end requests/responses and resource loading), and that
  • you have a low network latency and a stable wireless connection

You can fine-tune the responsiveness by changing the RenderTimeout in the Visionect Software Suite. Lower values mean a faster response time from a click to the screen refresh, but can cause partial renderings (e.g. missing images) as the page might not have been rendered completely when the ‘snapshot’ for the device display was taken. Your success will depend on how performant your web application is.

function okular.NoChange()

When a user registers a touch command on a client device’s screen, the device will wait for some kind of response from the Software Suite. The general rule is that for every client request, a response must be issued. This response can either be a new image or similar, or a NOCHANGE response which states that nothing has changed. This is not something users should be concerned about, as the Visionect Software Suite will handle it automatically. It should be noted, however, that it may take a while to detect possible viewpoint changes while the Software Suite is processing the click.

If you are sure about the fact that click on some element inside a webpage will change nothing, you can speed-up this process by calling this function and sending NOCHANGE response immediately. One must be aware that while device waits for a response it stays unresponsive and does not accept new clicks.

okular.NoChange();

General JavaScript extensions

Device status information

okular.DevicesStatus()

The function okular.DevicesStatus() will return a map of currently available client devices and their current status maps.

Example:

{
    "c04addea-54c2-4982-b27e-476d34e225ce":{ "RSSI" : 60, "Charger": 3, "BatteryLevel": 91, "Temperature": 24},
    "32021db4-74ba-5983-f27a-157d44e235ac":{ "RSSI" : 70, "Charger": 1, "BateryLevel": 13, "Temperature": 25},
  "27003600-0d47-3130-3830-333200000000":{"Battery":93,"Charger":3, "RSSI":61,"SleepMilis":8870,"Temperature":25,"TouchLastRelease":0}
}

Access information about the Visionect Server

var okular.nm_host

Stores the IP address of the Network Manager. This is important if you wish to access services from the Network Manager.


var okular.session_uuid

Stores the device UUID. The device UUIDs are globally unique (based on a device’s micro-controller UUID).


Trigger beep sounds from JavaScript

Warning

This feature only works with certain Visionect client devices, when coupled with an appropriate version of firmware.

Application developers can trigger different beep sounds directly from JavaScript by using the following function call:

okular.Beep(argument)

The following arguments are valid:

  • okular.BeepSoft
  • okular.BeepHard

The first one releases a silent, soft beep and the second one a louder beep.

//Example use:
okular.Beep(okular.BeepSoft)

Controlling the frontlight

Warning

This feature only works with certain frontlight-equipped client devices. Some devices might require additional configuration via the CLI to enable remote control of LEDs.

If the device has frontlight LEDs installed, it’s possible to control their brightness from JavaScript by using:

okular.SetFrontlight(value) // Valid argument values are 0 - 100

// Example use:
okular.SetFrontlight(60);

This will set the frontlight brightness to 60%. To switch off the frontlight, set the brightness to 0.

Onscreen keyboard

Warning

This feature only works on first generation Visionect 6” Signs. Newer client devices should implement the onscreen keyboard by using the JavaScript library.

A Visionect client device has the capability to display an on-screen keyboard if requested by the HTML rendering backend (formerly known as Okular). The backend will request the virtual keyboard to be displayed if:

  • The user clicked on a regular HTML input element of typed in a text or password.
  • The user clicked on a regular HTML textarea element.

The message that was typed by the user will be assigned to the input or textarea element value. It is also possible to apply a callback function to elements to be called after a successful text entry on the on-screen keyboard. This is done by providing an element with onKeyboardConfirm="callback_function" attribute.

<!--HTML EXAMPLE:-->
<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript">
            function kbd_check(el_id) {
                el = document.getElementById(el_id);
                    if (el) {
                        kbd_data = el.value;
                        console.log('Keyboard data:' + kbd_data);
                    } else
                        console.log('Element not found.');
                    }
        </script>
    </head>
    <body>
        <!-- input displays onscreen keyboard by default -->
        <input id = "test1" type="text" name="something" size=50 keyboard_layout="p"/>
        <!-- text area uses the callback function -->
        <textarea id = "test2" name="comments" onKeyboardConfirm='kbd_check("test2")'>
            Enter your comments here...
        </textarea>
    </body>
</html>

Keyboard layout

Warning

This feature only works on first generation Visionect 6” Signs.

To change the layout of the keyboard (portrait or landscape), add a keyboard_layout attribute to the HTML element. The valid values for the keyboard_layout attribute are l for landscape or p for portrait view. If the keyboard_layout attribute is not set, then a default layout will be used. The default layout is predicted from the display rotation setting.

<!-- HTML EXAMPLE: -->
<input type="text" name="something" size=50 keyboard_layout="l" />

Disabling the onscreen keyboard

Warning

This feature only works on first generation Visionect 6” Signs.

If you want to prevent the onscreen keyboard from popping up when a user registers a touch command, add a disabled attribute to the input element.

<!-- HTML EXAMPLE: -->
<form action="demo_form.asp">
  First name: <input type="text" name="fname"><br>
  Last name: <input type="text" name="lname" disabled><br>
  <!-- First name will display the keyboard popup, Last name will not. -->
  <input type="submit" value="Submit">
</form>

Button push event

Note

Supported on Visionect Software Suite 3.4 and newer.

If one or more physical buttons are pressed on the device, then the webkit service will dispatch a “button-push” custom js event. The event provides us with source device ID and with state of all buttons.

e.detail.device - source device uuid.

e.detail.state - bit-mask, where each bit represents the ON or OFF state for up to 32 different buttons. The actual hardware will probably support a much lower number of buttons. The least significant bit represents the first button.

e.detail.active - undefined. Reserved for future use.

There is a special helper function provided for help with bit masks

okular.buttonCheck(state, btnIndex):

mask button bit-mask.

btnIndex button index number. Its range is between 0 and 31.

Returns:

true or false, depending on the state of selected button.

document.addEventListener("button-push", handleButton, true);
function handleButton(e)
{
  // check state of button with index 2 by manfully checking bits.
  if( ((e.detail.state>>2)&0x1)>0 ) {
       ...
  }

    // check state of button with index 0 using helpper
  if( okular.buttonCheck(e.detail.state, 0)) {
       ...
  }
}

Fine-grained device configuration

Note

Only newer Visionect Software Suite firmware versions (0.5.0 or greater) support fine-grained device configuration as described below.

The following API is designed to change client device configuration - this are the things that usually require you to connect the device to the Micro USB configuration cable and configure by using CLI.

Warning

Changing some of the following settings may lead to a dysfunctional device. Use this function only if you know what you are doing.

Syntax:

okular.NewCommand(device-id, "Param", {"Data": param-json})

The param-json must be a JSON object with the following content:

{
    "Data": [
            {
                    "Type"   : paramID,
                    "Control": paramControl,
                    "Value"  : paramValue
            },
            ...
    ]
}

The JavaScript developer should define the following constants:

  • Constants for the parameter Control key:
var ParamRead       = 0, // Create a read request
    ParamWrite      = 1, // Create a write request
    ParamReadErrro  = 2, // Error reading the requested
    ParamWriteError = 3; // Error writing requested
  • Constants for the Type key:
List of supported parameter IDs
Type ID Description
0 TCLV Magic number
1 TCLV table version
2 Connectivity type
3 Wi-Fi ACK or NACK timeout and Waiting for next block timeout
4 Wi-Fi power saving timeout
5 Wi-Fi DTIM skip interval in msec
6 Mobile ACK or NACK timeout and Waiting for next block timeout
7 Mobile power saving timeout
8 Ethernet MAC address
9 Ethernet TCP retry count
10 Ethernet TCP retry timeout [100ms]
11 Ethernet ACK or NACK timeout and Waiting for next block timeout
12 Ethernet power saving timeout
13 IPv4 static IP
14 IPv4 static Netmask
15 IPv4 static Gateway
16 IPv4 static DNS server
17 IPv4 mode: 0=Static IP, 1=DHCP
18 Server IP
19 Server port
20 VCOM of Display 0
21 VCOM of Display 1
22 VCOM of Display 2
23 VCOM of Display 3
24 VCOM of Display 4
25 VCOM of Display 5
26 VCOM of Display 6
27 VCOM of Display 7
28 Display Type
29 Heartbeat interval
30 Network error retry interval
31 Proximity: offset calibration parameter
32 Proximity: threshold in %
33 Proximity: diode current in 10mA
34 Accelerometer threshold count
35 Accelerometer debounce count
36 Battery OFF threshold
37 Battery ON threshold
38 Battery threshold count
39 Frontlight map 0: PWM+LDR
40 Frontlight map 1: PWM+LDR
41 Frontlight map 2: PWM+LDR
42 Frontlight map 3: PWM+LDR
43 Frontlight map 4: PWM+LDR
44 Frontlight map 5: PWM+LDR
45 Frontlight map 6: PWM+LDR
46 Frontlight map 7: PWM+LDR
47 Frontlight threshold
48 Frontlight server control
49 System screens: 1=Battery, 2=Not connected, 3=Battery+Not connected
50 Touch mode: 0=OFF, 1=ON, 3=ON+Beep
51 Shipping mode: 0=OFF, 1=ON
52 Sleep mode disable: 0=Sleep mode enabled, 1=Sleep mode disabled
53 Command to save parameters to flash
54 Roaming mode: 0=Roaming disabled, 1=Roaming enabled
55 Roaming threshold in dBm
56 Roaming hysteresis in dBm
57 Writes EAP certificate chunk
58 Writes EAP certificate descriptor
59 Erases EAP certificate
60 EAP certificate 0 info
61 EAP certificate 1 info
62 EAP certificate 2 info
63 EAP certificate 3 info
64 EAP certificate 4 info
65 Wi-Fi SSID
66 Wi-Fi security mode: open, wpa2
67 Wi-Fi password
68 Wi-Fi: not used. Set to 0
69 Mobile APN string
70 Mobile security mode: none, pap, chap
71 Mobile username
72 Mobile password
73 Mobile: not used. Set to 0
74 Set Wi-Fi EAP method: TLS, TTLS/MSCHAPV2, FAST, PEAP/MSCHAPV2
75 Set Wi-Fi EAP password
76 Set Wi-Fi EAP username
1000 TCLV table version
1001 TCLV SCPU Frontlight Mode
1002 TCLV SCPU Frontlight map 0: PWM+LDR
1003 TCLV SCPU Frontlight map 1: PWM+LDR
1004 TCLV SCPU Frontlight map 2: PWM+LDR
1005 TCLV SCPU Frontlight map 3: PWM+LDR
1006 TCLV SCPU Frontlight map 4: PWM+LDR
1007 TCLV SCPU Frontlight map 5: PWM+LDR
1008 TCLV SCPU Frontlight map 6: PWM+LDR
1009 TCLV SCPU Frontlight map 7: PWM+LDR
1010 TCLV SCPU Frontlight PWM frequency in Hz
1011 TCLV SCPU Frontlight samplerate in sec
1012 TCLV SCPU Frontlight prefilter [0 .. 100]
1013 TCLV SCPU Frontlight postfilter [0 .. 100]
1014 TCLV SCPU Frontlight sensor timeout in sec
1015 TCLV SCPU Heater Mode
1016 TCLV SCPU Heater OFF temperature in °C
1017 TCLV SCPU Heater ON temperature in °C
1018 TCLV SCPU Device Mode
1019 TCLV SCPU Minimal OFF temperature in °C
1020 TCLV SCPU Maximal OFF temperature in °C
1021 TCLV SCPU Battery threshold in mV
1022 TCLV SCPU Frontlight PWM limit in %
1300 Command to push parameters to SCPU
1301 Command to pull parameters from SCPU
1302 Command to save parameters to SCPU

Note

The commands from 1000 onward are related to the Visionect 32” System Board only.

  • the Value key is a string value.

Example 1:

Get device IP address and server (gateway) IP address:

var paramPromise = okular.NewCommand("47003500-1351-3432-3434-373300000000", "Param", {"Data": [ {"Type":13, "Control":0, "Value": ""}, {"Type":18, "Control":0, "Value": ""}]})
paramPromise.then(function(data) {
    obj = JSON.parse(data);
    if (obj[0].Control == 2) {
        console.log('Error reading device IP address');
    } else {
        console.log('Device IP address is ', obj[0].Value); // convert from base64
    }
    if (obj[1].Control == 2) {
        console.log('Error reading server IP address');
    } else {
        console.log('Server IP address is ', obj[1].Value); // convert from base64
    }
});

Example 2:

Setting the device heartbeat:

changeHb = function(minutes) {
        console.log('setting heartbeat to ', minutes.toString(), ' minute(s)');
        var paramPromise = okular.NewCommand("47003500-1351-3432-3434-373300000000", "Param",
                        {"Data": [{"Type":29, "Control":1, "Value": minutes.toString()}]})
        paramPromise.then(function(data) {
                var obj = JSON.parse(data);
                if (Object.keys(obj).length == 0) {
                        document.getElementById("heartbeat").innerHTML = minutes.toString();
                        return;
                }
                var ctrl = obj[0].Control;
                var hb = obj[0].Value;
                console.log('Control:', ctrl);
                if (ctrl == 3) {
                        document.getElementById("heartbeat").innerHTML = '(write error ' + hb + ')';
                }
        });
}

Access the live view image

Note

This section applies to the Visionect Software Suite version 2.12.4 and above.

Since Visionect Software Suite version 2.12.4, the user application can fetch live view images using the following API:

  • The same image as one seen on device display(s):
okular.image.device(id, encoder, parameters);

  • The latest rendered image for a device. The image might or might not be the same as seen on device displays. When changing content, it takes some time for a device to synchronize its displays with the Software Suite. This is the reason why the display content and the cached image might differ.
okular.image.cached(id, encoder, parameters);

  • The latest image as seen by webkit backend viewport. If back-end is in a virtual screen mode, this will show merged view for all devices:
okular.image.backend(encoder, parameters);

Parameters:

  • id Target device UUID. Typically on a single device configuration (no virtual screen), the device UUID is implicitly known and the value can be safely set to null or an empty string “”,
  • parameters Optional parameters {[scale: scale], [display: id]},
    • scale Optional number parameter for image scaling 0<scale<=4.0
    • display Optional display ID (0, 1, 2, 3, ... NumDisplays-1). With okular.image.device() function, you can target a specific display.

Returns: promise

  • A resolved promise will contain:
{
      type,
      dataEncoding,
      data
};

Where:

  • type is a MIME content type, used to encode the image. The list below shows the valid type values and how they relate to the encoder function parameter value:

    • “bmp” -> “image/bmp”
    • “bmp-lz4_compress” -> “application/octet-stream” This is a normal bmp image additionally compressed with lz4 algorithm (see https://github.com/pierrec/node-lz4/)
    • “png” -> “image/png”
    • “jpeg”-> “image/jpeg”
  • dataEncoding string with value “base64”

  • data base64 string encoded image data

Should something fail, a promise is rejected with Error.

Example:

Let’s send a captured image to some server:

<!DOCTYPE html>
  <html>
  <head>
  <script>
  function postData(json) {
      var http = new XMLHttpRequest();
      var url = "http://localhost:8666";
      http.open("POST", url, true);
      http.setRequestHeader("Content-type", "application/json");

      http.onreadystatechange = function() {//Call a function when the state changes.
          if(http.readyState == XMLHttpRequest.DONE && http.status == 200) {
               console.log(http.responseText);
          }
      }
      http.send(json);
  }

  function render() {
          okular.image.device(null, "png").then(function(img) {
              img.origin="device";
              postData(JSON.stringify(img));
           }, function (err) {
              postData(JSON.stringify({err:err.toString(), origin: "device"}));
           })
   }
   window.onload=function() {
       setTimeout(function(){
           render()
       }, 10000)
   }
   </script>

  </head>
  <body>
  <h1>My Liveview Test</h1>
  <p>
   Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
  </p>
  </body>
  </html>

Access Live-View image

Since release 2.12.4 user application can fetch live view images using the following API:

  • okular.image.device(id, encoder, parameters); the same image as seen on device displays,
  • okular.image.cached(id, encoder, parameters); latest rendered image for device. The image might or might not be the same as seen on device displays. On content change, it takes some time for device to synchronize its displays with the server. The latter is the reason why the display content and the cached image might differ,
  • okular.image.backend(encoder, parameters); latest image as seen by the HTML backend viewport. If the backend is in virtual screen mode, this will show a merged view for all devices.
Parameters:
  • id target device UUID. Typically on a single device configuration (no virtual screen), device UUID is implicitly known and the value can be safely set to null or an empty string "",

  • parameters optional parameters {[scale: scale], [display: id]},

    • scale optional number parameter for image scaling 0<scale<=4.0
    • display optional display ID (0, 1, 2, 3, ... NumDisplays-1). With okular.image.device() function, one can optionally target specific display.
Returns: promise
  • a resolved promise will contain

    {
     type,
    
         dataEncoding,
         data
    };
    
where:
  • type is a MIME content type, used to encode the image. The list below shows valid type values and how they relate to the encoder function parameter value:

    • "bmp" -> "impage/bmp"
    • "bmp-lz4_compress" -> "application/octet-stream"- This is is a normal bmp image additionally compressed with lz4 algorithm see https://github.com/pierrec/node-lz4/
    • "pmg" -> "image/png"
    • "jpeg"-> "image/jpeg"
  • dataEncoding string with value "base64"

  • data base64 string encoded image data

or, if something fails, promise is rejected with Error

Examples

The following app will take its own “screenshot” and will append to its DOM tree:

okular.image.backend("jpeg", {scale: 0.5}).then(function(img) {
    // img holds base64 encoded image.

    // convert base64 string to a binary string
    var binary = atob(img.data);
    // copy binary string to ArrayBuffer
    var buffer = new ArrayBuffer(img.data.length);
    var view = new Uint8Array(buffer);
    for (var i = 0; i < img.data.length; i++) {
        view[i] = binary.charCodeAt(i);
    }
    // create blob
    var blob = new Blob( [view], { type: img.type });
    // blob URL
    var objectURL = URL.createObjectURL(blob);

   // create img element and attach blob URL to it
   var image = document.createElement('img');
   image.src = objectURL;
   //append img to DOM
   document.body.appendChild(image);

   // release blob URL
   URL.revokeObjectURL(objectURL);
}, function (err) {
   console.log(err);
})

Perhaps a more practical case on how to POST a captured image to a remote server using JSON API is as follows:

<!DOCTYPE html>
<html>
<head>
<script>
function postData(json) {
    var http = new XMLHttpRequest();
    var url = "http://localhost:8666";
    http.open("POST", url, true);
    http.setRequestHeader("Content-type", "application/json");

    http.onreadystatechange = function() {//Call a function when the state changes.
        if(http.readyState == XMLHttpRequest.DONE && http.status == 200) {
             console.log(http.responseText);
        }
    }
    http.send(json);
}

function render() {
        okular.image.device(null, "png").then(function(img) {
            img.origin="device";
            postData(JSON.stringify(img));
         }, function (err) {
            postData(JSON.stringify({err:err.toString(), origin: "device"}));
         })
 }
 window.onload=function() {
     setTimeout(function(){
         render()
     }, 10000)
 }
 </script>

</head>
<body>
<h1>My Liveview Test</h1>
<p>
 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
</p>
</body>
</html>

Device power management and sleep

Device power consumption and, as a consequence, its battery life can be significantly reduced by turning the device off (i.e. sending it into sleep mode) for periods of time when the display content does not need to be changed. While the device is in sleep mode, its display will continue showing the last content displayed.

Warning

While in sleep mode, client devices rely on an internal clock, making it impossible to wake them up remotely.

Sending client devices to sleep mode with okular.Sleep(periodMinutes)

Users can set the sleep mode settings using by Sleep Manager in Management Interface. To activate the Sleep Manager feature, go to Settings ->Global ->Features in the Management Interface and check the Sleep Manager box.ore information is available in Device power management and Sleep Manager.

It is also possible to send a sleep command to a device directly from its WebKit session with the help of a simple JavaScript command. This function will send the device to sleep mode for the amount of time specified in minutes.

//periodMinutes = int, device sleep time in minutes
//periodMinutes = 0, cancel unsent sleep command
okular.Sleep(periodMinutes);

The Visionect Software Suite will make sure that in the event of an early wakeup (caused by a device reboot or other external factors), the device will return back to sleep mode. This functionality can be canceled by invoking okular.Sleep(0).

Warning

You should call this function only if you know what are you doing. You have the power to send the device into the sleep mode for a very long time, but it might be difficult if not impossible to wake it up before schedule - especially if the hardware is physically inaccessible and cannot be power-cycled or rebooted manually.

Since the sleep command is in most cases sent immediately after the function call, you must be very careful not to call this function at the wrong time.

If you want to update the screen prior to sending the device to sleep mode, make sure you delay the sleep command - a call to this function can cause the device to go into sleep mode before the image is rendered on the device display.

This is even more important if you intend to send a device back into sleep mode every time it wakes up ("device-connect" event), as the problem might not be apparent the first time you execute the function (due to the async nature of JavaScript). To avoid the problems and difficulties described above, you can use the Software Suite’s internal sleep scheduling mechanism which will handle all the details for you.

Sleep Manager

Some users do not need a very fine-grained control over the sleep functionality and only need to schedule a periodical wakeup for the screen sync. If that is the case, than you can use Software Suite’s internal sleep scheduling mechanism which will handle all the details for you. See Device power Management and Sleep Manager for more. We recommend you use this mechanism if there is no real need to implement your own.

If the Sleep Manager is turned on and configured, then it will manage the periodical connect of the client devices. You can configure when the devices are to connect by using the Management Interface or by running the JavaScript functions created for this purpose:

okular.SleepSchedule(time, periodic);

The parameters are:

time: Time in minutes. periodic: The boolean parameter that defines how time is handled.

  • If periodic == true then the time parameter defines the the lenghts of time in minutes the device is to sleep.
//lets device to connect every full hour and refresh its display.
okular.SleepSchedule(60, true);
  • If periodic == false then the time parameter defines the minute of day the device is to wake up.
//sets the device to wake up at 2:00 am every day.
okular.SleepSchedule(120, false);
  • To remove the schedule run:
okular.RemoveSleepSchedule()

Example:

<!DOCTYPE html>
<html>
<head>
<script>
        window.onload = function() {
                //setup scheduler
                var time = new Date().toString();
                console.log("okular.SleepSchedule(60, true)");
                okular.SleepSchedule(60, true);
                document.getElementById("timep").innerHTML = time;
        }

</script>
</head>
<body>
        <p>Simple Page</p>
        Load Time: <p id='timep'></p>
</body>
</html>

React to a connect event

The device connect event functionality can be used to set a device’s session to a certain state when a device disconnects (example: printing out “out of range” on the screen) or can be used as a periodical sleep setup in conjunction with "okular.Sleep(periodMinutes);". When a device connects to the Software Suite, the "device-connect" event is triggered and provides two detail parameters.

  • Connected device uuid: e.detail.device

  • Connect reason: e.detail.reason

    The possible values are:

    • "unknown"
    • "reboot"
    • "wakeup"
    • "heartbeat"
    • "logs full"
    • "connection error"
    • "protocol error"
    • "command line"

Example:

document.addEventListener("device-connect", handleConnect, true);

function handleConnect(e)
{
    console.log("device-connect", e.detail.reason, e.detail.device);
}

Note

When a device connects to the Visionect Software Server for the first time, or when a new WebKit session is created, a connection event is not triggered.

Configure device’s hardware settings

The following API is designed to change a client device’s configuration, requiring you to connect the client device to the Micro USB configuration cable and configure by using CLI. As an alternative way, you can also change a device’s configuration by using TCLV commands as described in js-device-config.

Note

Use the following configuration settings only when sure of what you are doing.

Change or disable the heartbeat interval

The following command changes the device heartbeat interval - the time after which the device will report back to the Software Suite.

okular.SetHeartbeat(minutes);
  • minutes is the new HB interval for device(s)
  • limitations: 0 <= minutes < 60
  • disabling HB: if minutes == 0, HB will be disabled

Enable/Disable the battery indicator and touch

Configure a client device’s battery indicator, connection indicator and its touch panel operation.

okular.ConfigureSystem(batteryIndicator, touch [,disconnectedIndicator]);

bateryIndicator (bool) Sets the device to display a “battery empty” display when the battery is depleted.

The supported values for the bit-field touch (bool or int) are:

// system command touch options
okular.SystemTouchOff          = 0x00000000; // touch is disabled
okular.SystemTouchOn           = 0x00000001; // touch is enabled
okular.SystemTouchOnBeep       = 0x00000003; // touch is enabled and device will beep when touched

Note

In Visionect Software Suite version 2.7 touch was always a boolean type. Depending on its value, it switched touch support on device ON(true) or OFF(false). This behavior is deprecated in Software Suite version 2.8 +, but still supported. The following touch options will only work on devices with the touchscreen and firmware version that supports buzzer.

disconnectedIndicator (optional bool) Sets the device to display a “disconnected” screen when disconnected from the network.


Configure the battery indicator

Configure when the battery indicator is displayed on screen. The default values should work best, but you could tweak this to suit your needs.

okular.ConfigureBattery(tresholdOff, tresholdOn [, tresholdCount = 1])
  • tresholdOff Battery integer value in [mV]. The value that client devices use to decide if the battery is empty and display an “battery empty” display.
  • tresholdOn Battery integer value in [mV]. The bootloader will refuse to boot if the battery is lower than this value.
  • tresholdCount - (optional) Integer that defaults to 1. If the battery is being charged, this count lets the bootloader know how many times it should compare the battery to the tresholdOn before giving up.

Example:

okular.ConfigureBattery(3497, 3696, 1).then(function(result) {
     console.log(result); // Success: stuff worked!
 }, function(err) {
     console.log(err);
     // Error: Maybe retry later.
 });

Configure a client device’s display VCOM

For optimal display drawing performance, each Visionect client device display comes with it’s optimal VCOM voltage. The API allows us to set the VCOM voltages for up to 8 displays. Since VCOM is always a negative value, the API omits the minus sign, and also accepts absolute values. The value should be sent in [mV].

okular.SetVcom(vcomArray)

Warning

Your client device is already configured with the VCOM setting, so it is not recommended to change it. If you have accidentally overwritten the VCOM or need more information about this setting, please contact our support .


Configure the device display type

Visionect firmware supports many different display types. Different display types support different waveforms and different sizes. A device can render images correctly only if it knows what type of display is connected to it. Do not change this setting unless you know the display ID you should use.

okular.SetDisplayID(displayID)

Warning

Your client device is already configured with this setting, so it is not recommended to change it. If you require more information about this setting, please contact our support .


Uploading custom display images, file-system support

Note

This feature is available from Visionect Software Suite 3.2 onward.

Uploading custom images

Uploading an image file to the Visionect client device. The function takes a base64 encoded PNG image and uploads it to the electronic paper sign. The server transforms the PNG image to the device image format before uploading it.

okular.SetImage(target, name, imageData)
Parameters:
  • Target device UUID string.
  • The name parameter should be set to “disconnected”, as only changing the disconnected image is currently supported.
  • An imageData base64 encoded PNG image in the data URL string format

Returns: Promise, which is resolved ether with ‘Error’ or with the device file checksum string.

Example:

okular.SetImage(okular.device_uuid, "disconnected", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC").then(function(result) {
      console.log(result); // Success: print uploaded checksum
  }, function(err) {
      console.log(err);
      // Error: Maybe retry later.
  });

Displaying a list of files on device

The API allows the user to list the files located on the device:

okular.ListFiles(target)
Parameters:
  • Target device UUID string.

Returns: Promise, which is resolved ether with ‘Error’ or with the object, containing a file list in the following format:

{"filename1":{"checksum":  string, "size": string }, "filename2":{"checksum":  "...", size: "..." }, ... }

Example:

okular.ListFiles(target).then(function(result) {
      console.log(result); // Success: stuff worked!
}, function(err) {
      console.log(err);
      // Error: Maybe retry later.
});
// Output: {"disconnected.pv2":{"checksum":"1960206407","size":"74975"}}

Web session & page reloading watchdog timer

Visionect Software Suite version 2.6 introduced a new page reloading watchdog timer. To prevent the web app from “freezing”, users can now turn on a page reload time-out for each device session in the Management Interface. If the app freezes, it will simply be reloaded after the set time-out, making the client device usable again. A working app can reset the watchdog timer before it would time out. The app can start the timer (if it is not already running), can check the timeout value which was used to start the timer, and can stop the timer.

  • Start or restart the watchdog timer:
    • The function:
okular.ReloadTimeout(seconds)

starts up the timer, while stopping any old timers that might have already been running. The function accepts the timeout in seconds as a parameter.

  • The function:
okular.GetReloadTimeout()

checks the timeout value used when the timer started. The function returns null if the timer is disabled, or returns the timeout value in seconds used when the timer started.

  • Stop the watchdog timer:
    • The function:
okular.ReloadTimeoutStop()

stops the watchdog timer.


Handling command errors with JavaScript “Promise” feature

The use of the new JavaScript ‘Promise’ feature is encouraged to handle any request errors.

For example:

  okular.Reboot().then(function(result) {
    console.log(result); // Success: stuff worked!
}, function(err) {
    console.log(err);
    // Error: Maybe retry later.
});

This applies for several functions like:

okular.Beep(level),
okular.SetFrontlight(level),
okular.Sleep(periodMinutes),
okular.SetHeartbeat(minutes),
okular.TouchUpdate(),
okular.ConfigureBattery(tresholdOff, tresholdOn, [tresholdCount = 1]),
okular.SetVcom(vcomArray),
okular.SetDisplayID(displayID) and
okular.Reboot().