Creating Custom Web Pages

Custom web pages support requires SmartServer IoT 2.6 or higher.

You can create custom web pages for the SmartServer that enable users to interact with devices in a standalone or LON network. These custom web pages can query and update device datapoints served by the SmartServer. You can access the SmartServer directly by using the IAP/REST and IAP/MQ APIs. This section describes the process of creating a web page with the IAP/REST API. Similar requirements are needed for web pages created with the IAP/MQ API.

This section consists of the following:  

Custom Web Page Examples

The following images show examples of custom web pages that can be created for the SmartServer.  The SmartServer IoT browser web page example (first on the left) is available on the EnOcean Github repository.



To access devices and their datapoints, the devices must first be added to the SmartServer. In Device Management Mode (DMM) or standalone mode, devices are created through the SmartServer CMS (as described in Discovering, Defining, or Importing Devices), IAP/REST API, or IAP/MQ API. In LON Independent Management Mode (IMM), the devices are added through the IzoT Net Export Tool

SmartServer 2.8 introduced datapoint localization, presets, and override priorities. These settings are configurable for each datapoint specified in device type by using the CMS Datapoint Properties widget or DLA file. 

Localization can be used to transform datapoint values based on regions.  For example, if a device's datapoint values are in Celsius, but you want to see them in Fahrenheit, you can use localization to do the conversion automatically.  Localization can also be used to limit floating point values to a specific number of decimal places. To differentiate between the localized and non-localized values, the non-localized value is sometimes called the IAP value.  

Presets allow you to create normalized values (like "ON" and "OFF") that can be used for many SmartServer functions, like scheduling. A preset is a text string and corresponds to a specific value. For a binary datapoint you can specify a preset of "ON" to be a value of "true" and a preset of "OFF" to be a value of false.  For another datapoint "ON" may be a value of 1 and a preset of "OFF" means a value of 0.  When you write to a datapoint using a preset, the REST request will use the preset name, but the SmartServer will send the IAP value to the edge device.

For example, if you want to turn two different type of devices (a light and a HVAC device) on at 9 AM, you can create ON presets for the datapoint on each device, and then create a single schedule event at 9 AM that specifies both of the datapoint and uses a preset of  "ON". The alternative is to create separate events for each device.

Only IAP values are sent to edge devices. Localization values and presets are mapped to the corresponding IAP value before the IAP value is sent to edge devices.  Localization and presets are used internally to the SmartServer allowing you to provide more meaningful representation of data than may be provided by a IAP value. That is, a user may understand turning a switch ON or OFF better than changing a datapoint value between true or false, or 1 or 0.

Override Priorities allow you to give preference to certain types of writes. Priorities are 1 (highest priority) through 16 and Normal (17). Datapoints default to Normal, except for BACnet. Overrides are used for functions like schedule events so that you can make exception schedules for holidays or special events. Priorities need to be taken into account when doing writes. Priorities are mainly only used internally in the SmartServer to specify which value is sent to the edge device. The exception is for BACnet datapoints, any time you write to a BACnet datapoint the new value and the write priority is sent to the BACnet device. For other protocols, the write priorities are not sent to the edge device. When writing to a datapoint you can specify the priority or send it at Normal priority. If your web page writes a datapoint at priority 15, but there is an existing schedule event for this datapoint at priority 8, then the priority array will get updated for priority 15 but the current value is not changed and your REST request will get an HTTP 422 error.  That is, you can only change the datapoint current value (as seen in the CMS Datapoint Browser widget) when the priority in your write request is the same or higher priority. There is no built-in mechanism for clearing priority levels so you must be careful when you use them. When a schedule event is complete, it may relinquish a priority and so the next active priority value is used. The CMS Datapoint Browser widget can be used to relinquish priorities and there is a REST API that can be used to relinquish priorities

When developing your custom web page or application, you first need to know what features your web page needs to support. As an example, if your web page is working with BACnet devices, you may need to send all updates at priority 8. For other protocols, you may decide to send your write request at Normal priority (17). If preset values are supported then you will need to check if the presetValue reported in the GET response or WebSocket update is null. If not null you would display the preset name in your Web page, but if the preset value is null then you would then display the localized or IAP value.  You may want to always display the localized value if you think that a user now or in the future will use localization.  If a datapoint hasn't been configured for localization then the localized value and IAP value are identical, thus using a localized value gives you the most flexibility.

There are different ways to get datapoint updates:

  1. GET using Response data
  2. GET using WebSockets – only one web page with WebSockets can be used at a time for a single user login.
  3. Get using Datapoint Tags

Datapoint Naming

Each datapoint point has a datapoint instance name and a datapoint XIF name. The datapoint instance name is what you see in the CMS Datapoint Browser widget default view. The datapoint XIF name is what is specified in the device XIF file and what you see in the Datapoint Properties widget and DLA file. You can see the datapoint XIF name in the CMS Datapoint Browser widget Details view. In most cases, the datapoint instance name is the same as the datapoint XIF name. REST API requests that specify datapoint names use the datapoint instance names, but you can use "*+xifName==" to specify the request using XIF names.  

Each device has a device ID and DID.  Device ID is used for most REST requests using an identifier for the device. Device DID is used for dpQualifiers and for MQTT tokens.

Reading Datapoints

REST API requests for reading datapoint values will show the localized, non-localized (IAP value), and preset value (set to null if the value does not map to a preset value). 

When writing, you will need to decide on the REST request to use based on whether you are writing to a localized value, non-localized value (IAP value), or preset value, and whether you are writing with or without priority as there are different REST requests for each. Only IAP values are sent to edge devices. Localized values and preset values are only used internally, for MQTT and REST API requests, and for showing datapoint values in the CMS or custom web pages. IAP values and localized values are identical if localization is not specified in the CMS Datapoint Properties widget or DLA file. If there is any chance that someone is going to use localization, then you should use the localized REST request for writes.

A datapoint value may be equal to null when you first access a device or datapoint. The a null value means that the datapoint has not been read by the SmartServer yet. This can happen when you first add a device, after a reboot or power cycle.  If monitoring is enabled for a datapoint then when you first read this datapoint then it may have a non-null value. If monitoring is not enabled for the datapoint you can use on-demand GET request to get the latest value.  Since initially the datapoint value is null, your custom Web page needs to support a datapoint value being null as well as the value from the device.

On-demand GET using dpQualifer

On-demand GET requests allow you to specify a list of datapoints. Each datapoint is specified by a dpQualifier.

Before issuing your on-demand GET using the dpQualifer, your web page needs to get a list of device(s) based on device name or device type.  You can then determine the SmartServer scId and the DID for each device, which is used to create a dpQualifier.

dpQualifier format

    <smartServer scId>/<protocol>/<device DID>/<block Name>/<block Index>/<datapoint XIF name>

Example dpQualifer:


For most custom web pages, you will normally specify a datapoint pathname and build up the dpQualifier at run time.

Datapoint path format

    <device name>/<block name>/<block index>/<datapoint XIF name>

Example to get the nvoLuxLevel value from three devices:


    "Sensor1/device/0/nvoLuxLevel", "Sensor22/device/0/nvoLuxLevel", "Sensor33/device/0/nvoLuxLevel"

Convert the datapoints to dpQualifiers.


Before sending the request to the SmartServer you need to replace "/", spaces (" "), "[", and "]" with their ASCII codes. Replace "/" with "%2F".


On-demand GET using Datapoint Tags

Datapoint tags can be used to request datapoint values for multiple datapoints in a single request. Datapoint tags consist of a tag (also called tagName) and a tag.value. The tag is a unique identifier (no other web page or internal SmartServer function should use this tagName). The tag tag.value is used to differentiate datapoints on a single web page. The tag names typically include the web page developer's company initials and some other unique identifier, if multiple people or groups within the company create web pages, plus a unique name for the web page (such as, "xyz_dashboard =1"). Tag value (tag.value) is optional. That is, you should only set a tag.value if you need it.

For example, if you have a building with three floors and want a master web page and a web page for each floor, you could:

  • Create a tag called "xyzjd_floor1=1", where "xyz" represents XYZ company, "jd" stands for John Davids, "floor1" which is this unique web page and tag.value of "1".

  • Assign different tag values to each web page, such as "xyz"="main" for the master web page:
    • Assign "xyzjd_floor1=1" for floor one.
    • Assign "xyzjd_floor2=1" for floor two.
    • Assign "xyzjd_floor3=1" for floor three.

If you are not using tag.value, then for floor1 the tag would be "xyzjd_floor1".

For SmartServer release 3.6 and higher

Datapoint tags can be assigned in the Datapoint Properties Widget, or by your custom Web page. Since the Datapoint Properties Widget is for device types then all devices of that device type will have that specific tag for the specific datapoint. If you only want to add the tag to one device then you will need to add the tag with your custom Web page.

For SmartServer 3.5 and prior releases

Datapoint tags are assigned by your custom Web page. Typically this is done only the first time this Web page is used. All susequent access to this Web page only uses GET request with the tags. 

To assign a tag to a specific device and datapoint

POST  /iap/devs/*+name==Sensor1/if/LightSensor/0/nvoLuxLevel/tags    Payload {"xyz_floor1"="1"} 

To get datapoints with a specific tag

Get /iap/devs/*/if/*/*/*+tag==xyz_floor1&tag.value==1/value?pg=1&sz=30&max_age=1

Typical Web page

A typical web page shows multiple datapoints from multiple devices. Datapoints are usually defined as a datapoint path, such as Sensor1/LightSensor/0/nvoLuxLevel. You can determine the names of datapoints by going to the CMS Datapoint Browser widget, looking at a DLA file, or issuing a REST API command. To see datapoint properties for a device named "Sensor1", you could run the following REST API GET:  /iap/devs/*+name==Sensor1/if/*/*/*/*

GET request pagination should be used when using datapoint tags or wild cards in the GET request. Pagination is used to reduce the number of entries returned each request. For the request above, the first request would be /iap/devs/*+name==Sensor1/if/*/*/*/*?pg=1&sz=30. If there are more than 30 datapoints in the sensor device, you would have to make more requests using the snapshot number provided in the first request response. If there were more than 30 datapoints and the snapshot number returned in the first response was 48378, then the next request would be  /iap/devs/*+name==Sensor1/if/*/*/*/*?pg=2&sz=30&xs=48378. You would continue sending the second request with a new "pg" number until the web page received all the datapoints.

Datapoint values can be scalar (that is, a single field or a single piece of data) or structured (that is, the datapoint contains multiple fields like SNVT_switch which has both a "state" and a "value"  field). 

The SmartServer is based on Linux OS, therefore, web page names are case sensitive. This means that "Test.html" and "test.html" are different web pages.

There are two types of poll rates that are important for web page development. One poll rate is how often you send out a GET request to get datapoint values from the SmartServer. When poll rate is mentioned in web page development, it is usually referring to the GET poll rate. This rate is related to getting the cached data from the SmartServer. The second poll rate is related to the SmartServer getting live data from the end device. There are two ways of getting live data. One way is to configure monitoring in the CMS Datapoint Properties widget. The other way is to do on-demand polling using maxage (Get the latest cached value, but if the datapoint hasn't been read within the specified maxage time, go on the wire and get the latest value). For some device protocols the SmartServer automatically has the latest values (like Internal LON devices). For others, like external LON devices, you may need to set up monitoring (polling or event driven) in order to see live data.

In most cases, you will want the Datapoint Properties polling to be set for slow polling. To get faster updates for your Web page you will use on-demand polling (maxage).

Three sample web pages are provided to help you get familiar with creating a custom web page for the SmartServer. The "Simple Read" and "Simple Write" examples are intended for you to understand how to read and write datapoint values. These examples are for basic understanding, but are missing background polling of datapoints that is normally used for most SmartServer custom web pages.

The Simple Sensor example (simplesensor.html) shows a fully working example. The Simple Sensor web page was designed to be used as a web page template. You can modify this web page in order to learn more about how to design a SmartServer custom web page. A Custom Web Page Tutorial section shows how to modify the Simple Sensor web page for a different set of datapoints.

The following resources are available at  SmartServer-IoT Example Repo under web pages: 

  • Demo folder containing Simple Read, Simple Write, and REST API tester.  SFTP the demo folder to the /var/apollo/www/user directory.

  • Simple Sensor source code, which provides a starting point for creating your own custom web pages. SFTP the simplesensor folder to the /var/apollo/www/user directory.

  • Optional graphics that you can use for your custom web pages. SFTP the images directory to the /var/apollo/www directory. 
    Click to download the Web Page Graphics.

Note: Datapoint monitoring for external LON Devices is disabled by default, and only updated if you enable monitoring for that datapoint. Therefore, datapoint values are not current or valid until datapoint monitoring is enabled. Datapoint monitoring rates can be configured through the REST API, the CMS Datapoint Properties widget, or by importing a DLA file. With SmartServer 2.6 or higher, your web page can use on-demand request to see datapoint updates.


Writing to Datapoints showing with and without using priorities : Override Priorities 1-16, Normal (17); 1 is highest priority.

  1.  Writing using presets:
    PUT: /iap/devs/+*name==PulseGen1/if/device/0/nviHVACMode/overrides/17/presets/value          Payload: ON

    PUT: /iap/devs/+*name==PulseGen1/if/device/0/nviHVACMode/overrides/17/presets/value          Payload: ON

  2. Writing using localization:
    PUT:  /iap/devs/*name==PulseGen1/if/device/0/nviCount/overrides/17/localization/value         Payload: 10

    PUT:  /iap/devs/*name==PulseGen1/if/device/0/nviCount/localization/value                              Payload: 10

  3. Writing using IAP value:
    PUT:  /iap/devs/*name==PulseGen1/if/device/0/nviCount/overrides/17/value         Payload: 10

    PUT:  /iap/devs/*name==PulseGen1/if/device/0/nviCount/value                              Payload: 10


HTTP 204 means the value was sent to the SmartServer.

HTTP 422 means that the value was sent to SmartServer and datapoint override array was updated, but that the current value is not updated as there is a higher priority already assigned to this datapoint. When the higher priorities are relinquished this value will be used.

See for more information on how to create web page using Javascript, HTML, and CSS.

Datapoint Tag Web Page REST API Workflow

The following example provides the IAP/REST steps for the floor1 web page with three lux sensors:

      This workflow is demonstrated in the Simple Sensor web page example so you do not need to develop it if you use simpledriver.js for your web page.

  1. Perform a single request to get all three datapoint values with one request. 

         Get  /iap/devs/*/if/*/*/*+tag==xyz_floor1&tag.value==1/value?pg=1&sz=30 

    The first time you try to access a SmartServer web page you may get an HTTP 401 Unauthorized error, which means the user needs to log into SmartServer.

    Log into the SmartServer web server. 
    Use the provided /var/apollo/www/user/login.html (change login1.html to login.html), or send the appropriate login REST API request.
          POST  /iap/auth/login     Payload  {"username":"tom", "password":"test"} 

  2. If the datapoint does not show up in the first GET response, you may need to add a tag to the datapoint.
    The following example shows how to add tags for each device on floor1:

    Assign a datapoint tag for each datapoint on the web page (must be done only the first time the web page is opened by a web browser):
         POST  /iap/devs/*+name==Sensor1/if/LightSensor/0/nvoLuxLevel/tags    Payload {"xyz_floor1"="1"} 
         POST  /iap/devs/*+name==Sensor2/if/LightSensor/0/nvoLuxLevel/tags    Payload {"xyz_floor1"="1"} 
         POST  /iap/devs/*+name==Sensor3/if/LightSensor/0/nvoLuxLevel/tags    Payload {"xyz_floor1"="1"} 

  3. If more datapoints are returned from the GET request than you are using for your web page, then remove the tags from the unwanted datapoints.
    Datapoint tags should be unique for each custom web page.

  4. Issue the following request periodically to see datapoint value updates (set up monitoring for the datapoints individually through the REST API, CMS Datapoint Properties widget, or by importing a DLA file to see changes):
         Get /iap/devs/*/if/*/*/*+tag==xyz_floor1&tag.value==1/value?pg=1&sz=30&max_age=1
         Get /iap/devs/*/if/*/*/*+tag==xyz_floor1&tag.value==1/value?pg=2&sz=30&xs=45

The "xs" snapshot number changes for each "pg=1". Use this new "xs" number for all other "pg" requests.
max_age should only be used for external LON device datapoints.

For external LON devices only, starting with SmartServer IoT 2.6, you can use on-demand polling "max_age" (in seconds) for external LON devices with your GET request.  Do not use "max_age" for any GET tags that include devices other than LON devices as this will cause the SmartServer CPU to be used up. That is, if you use "max_age" for internal LON devices, BACnet, Modbus, or IOX datapoints, the CPU bandwidth will be consumed and the SmartServer processes will become very slow.

To support custom web pages with LON and non-LON devices, you will need to use different GET tags. For each GET tagName, you will need to run the workflow above. To support all devices types, your custom web page may need up to four TAG types: no max_age, no max_age onetime read, max_age and max_age onetime. 

The Simple Read/Write Web Page Example simpledriver.js file supports all four TAG types. All you need to do is to change the web page tagname and the simpledriver.js will automatically create up to three more Tagnames, which are used to send up to four different GET requests (depending on what datapoint types you are using). A tutorial on how to create a custom web page with the Simple Read/Write example is provided in the Custom Web Page Tutorial. A detailed description of the example is provided below.

For external LON devices only, when using pagination, specify max_age only in the pg=1 request. On-demand polling allows you to see datapoint updates without configuring datapoints polling or event driven updates. Since the total monitoring rate is 18, you might set "max_age" to 5 polls per second to help ensure that the total remains under 18. On-demand polling allows you to get fast updates for your web pages and allows you to set reasonable poll rates for normal usage (60 seconds for important data and 15-60 minutes for low priority data) and no polling for all other datapoints.

Enabling Custom Web Pages (SmartServer 2.5 Only)

The SmartServer IoT 2.5 default configuration does not come with custom web page support enabled. With SmartServer IoT 2.6 or higher, custom web pages are automatically enabled.

  • When updating a SmartServer 2.4 or 2.5 to 2.6 with the glpo file, you will still need to use these instructions to enable custom web pages. 
  • If you re-image the SmartServer to 2.6, then custom web pages are automatically enabled.

To enable custom web page support, you need to make certain changes to the following two files:

  • /etc/nginx/sites-available/
  • /etc/nginx/sites-available/apollo.self

The following changes must be made to both files on each SmartServer that will run the custom web page:

  1. Backup the and apollo.self files either on the SmartServer or to your computer. These files are unique per SmartServer so you will need to do this on each SmartServer.

  2. Edit /etc/nginx/sites-available/
    You can do this with WinSCP or by coping the file to your computer and using notepad or any other text editor. Save as Text only.

  3. Look for the following two entries:

    # Everything Else 


    # IzoT Router (PHP Server)

  4. Copy the following text to a text editor (such as notepad.exe) on your computer or Writer so that all text formatting information is removed:

        # CMS REST API Server
        # 1) pass request to Jetty (CMS REST API Server)
        location /iap {
        #rewrite ^/iap(.*) /$1 break;
        proxy_pass https://localhost:8443;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass_header Server;

  5. Copy the text from your text editor to just before the following entry:
    # IzoT Router (PHP Server)

  6. Save the file.

  7. Repeat steps 2-6 for /etc/nginx/sites-available/apollo.self.

  8. Re-start nginx by running the following command in the SmartServer console, or by rebooting the SmartServer.

  sudo nginx -s reload 

The following example shows the added content (shown in red):

# Everything Else - TBD
# 1) check for maintenance page and display if it exists
# 2) check for local (static) file
# 3) check for local directory
# 4) pass request to IzoT Server
#location / {
# try_files /maintenance.html $uri $uri/ @izot-server;

# 1) pass request to Jetty (CMS REST API Server)
location /iap {
proxy_pass https://localhost:8443;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_header Server;

# IzoT Router (PHP Server)
# 1) verify PHP file exists
# 2) pass request to PHP Server
location @apollo-config {
# APOLLO try_files $uri = 404;
# APOLLO fastcgi_split_path_info ^(.*?\.php)(/.*)$;
# APOLLO fastcgi_pass unix:/run/php/php7.0-fpm.sock;
# APOLLO fastcgi_index index.php;
# APOLLO include fastcgi_params;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
fastcgi_read_timeout 300;

auth_basic "Restricted";
auth_basic_user_file /etc/apollo/.htpasswd;

Saving Custom Web Page Files

Custom web pages should be located in the following SmartServer directories to ensure that custom files are not deleted with SmartServer updates:

  • /var/apollo/www – location for all custom web pages
  • The following sub-directories are provided for common files (files used by multiple web pages):

    • /var/apollo/www/user – custom web page files html, javascript, images, and css
    • /var/apollo/www/js – common JavaScript files
    • /var/apollo/www/images – common image files
    • /var/apollo/www/css – common style sheets

  • Required files for new home page:
    • /var/apollo/www/user/home.html

  • Required files for login prompt:
    • /var/apollo/www/user/login.html
    • /var/apollo/www/user/images/LoginLogo.png

Adding a Login Prompt

Starting with SmartServer release 3.5 or higher the SmartServer defaults to enhanced security which checks to make sure your password meets the enhance security requirements (like being 14 characters or more). 

If you use the Original login1.html page, provided on the SmartServer then the login Web page may get stuck. You can either disable enhanced security (see ssh/console commands) or use the new login1.html file included with SmartServer release 4.0 and higher.

For the apollo user you should only change the password using the SmartServer Configuration System Web page and not using the CMS User Widget. Also password reset email is not supported for the apollo user. All other users you can request a password reset email (if SMTP is configured), or change the Password with the CMS User Widget or with the SmartServer release 4.0 or higher updated login1.html page.

The SmartServer comes with a built-in login prompt, but by default it is not enabled for your custom web pages.

  1. With SmartServer IoT 2.6, an example Login1 prompt and LoginLog1.png are provided which you can use with your custom web page. 

  2. You need to rename these files in order to use them as a SmartServer software update may change these files.

  3. You may customize the login prompt. One common modification to the login prompt is to change the company logo to your company logo, or the end customer company log.

  4. To use the login prompt, you need to rename login1.html and LoginLogo1 by removing the "1" from each.  
    a. Change the names of the file.



    SmartServer 3.6 and previous releases

b. Change the login.html file link to point to LoginLogo.png instead of LoginLogo1.png by removing the "1" at the end.

<img src="../images/LoginLogo1.png1" alt=" " class="avatar">

<img src="../images/LoginLogo.png" alt=" " class="avatar">

c. To logout, your custom web page needs to do a POST with no payload (payload empty)


https://<SmartServer-IoT IP Address>/iap/auth/logout

Changing the SmartServer Home Web Page

To replace the current SmartServer IoT home page, you need to provide a web page called home.html at the following location (by default, this file does not exist):  

  • /var/apollo/www/user/home.html

When the SmartServer sees the home.html file, it uses this web page as the home web page instead of default home web page.

An example home web page is provided called home1.html. You can remove the 1 to rename it to home.html and reboot the SmartServer.
The SmartServer will automatically begin using this new home web page.

  • /var/apollo/www/user/home1.html

You can customize home.html.

home1.html may be modified during a SmartServer update.  

If you decide to keep the example home.html page, then you should change the "Custom Web Page" to point to your custom web pages.
This button currently defaults to the dummy web page below, but you can point to any custom web you create.

  • /var/apollo/www/user/custom/index.html

Web Page Design Considerations

To access your custom web pages you will need to replace the SmartServer IoT home web page and provide a login prompt.

  1. Since web page names are case sensitive, you may want to use all lower case so as not to confuse customers.

  2. You need to decide if your custom web page is going to show presets, localized values, or IAP values.
    1. If preset value is not null, show preset value.

    2. If preset value is null, show localizaed or IAP values.
      1. Always reading and writing localized values gives your custom web page the most flexibility. Customers can later add localization to a datapoint without the need to release a new custom web page.

  3. You need to decide how to poll for datapoint updates (On-demand GETS using  dpQualifier or datapoint tagNames).  
    1. On-Demand GETs using dpQualifier can provide datapoint updates with or without web sockets. 
      1. Only one WebSocket web page, CMS web page or custom web page, can be used at a time per user login. To use more than one WebSocket web page, login using different user logins. 
      2. Your web page needs to create the dpQualifier during run time, by first reading all devices or devices with certain devices types. Next, you will create a list of dpQualifiers for the datapoints you want to show on your web page.

    2. On-demand GETs using tagName. Each web page must have a unique datapoint tagName in order to get updates for those datapoints used on the web page and to reduce traffic when on-demand polling is used. 

  4. When working with structured datapoints, you can either show the entire datapoint value or a single datapoint field value. You need to be careful when writing a structured value as you need to write the entire value. That is, you cannot write to a single field.

  5. When writing to a datapoint value, the SmartServer PUT request may return back HTTP 204 whether or not the URL and payload are correct.
    1. One way to determine if a datapoint field is a number or a string is to read the value and then check if field is number, string, or object using the JavaScript "typeof" operator.
      1. To help determine datapoint formatting and type you can get the datapoint type information (SNVT,UNVT, SCPT or UCPT). This is extremely useful for LON devices as you can determine if the datapoint or field is an integer, float, string, Boolean and the range of values. The ranges are for the datapoint type and may not match what the actual device supports. For other protocols like BACnet or Modbus, unless you create specific UNVT or UCPT for these devices your code won't know what ranges are supported. In most cases, the standard SNVT, UCPT or base types (scalar, floar) are used for BACnet and Modbus datapoints so the datapoint type will not inform you what ranges are supported.
      2. Example of getting the datapoint type information for SNVT_switch 
        1. GET /iap/dp/types?dpTypeName=SNVT_switch
    2. Your source code should validate any write data before doing your PUT request.

  6. The REST API only allows you to write the complete datapoint value. That is, you cannot just write to a datapoint field value. You normally do a read modified write on structured datapoints
    1. If writing to a single field, you need to do a read modified write by either using a default value or using the last read value.

    2. When writing to some structured datapoints, a read modified write may not always work.

  7. When writing to a datapoint you need to have a feedback delay before responding to new updates for this web page. 
    1. If you do not add a feedback delay (say 10 seconds), then you may see the value flicker between two values.

    2. After you write to a datapoint and update all other HTML elements using this input datapoint, when you read the datapoint again (GET request) the old value may show up and then sometime later the new value shows up.
      1. This happens because there is a polling value and the new value showing up in the REST API. For example it can take up to 7-10 seconds after you write a value before the value is actually read (during next poll request) and seeing the change in the web page. During this time, it is possible that the old value read during a poll request before doing the write has just propagated up to the web page, and then 7-10 seconds later, the new value shows up. This behavior may cause you to think the value is flickering when it is due to polling delay. 
      2. Adding a feedback time after writing to a datapoint reduces this flicker delay. Any datapoint updates during the feedback time is ignored.

  8. Getting  real-time updates from devices.
    1.  On-demand polling (max_age) is supported with SmartServer IoT 2.6 or higher. SmartServer IoT 2.5 does not support on-demand polling.
      1. When on-demand polling is not used, you need to enable datapoint polling in order to see datapoint updates you need to enable polling.
        1. For external LON devices only, if you are using DMM mode, you have the option to enable polling or event-driven data. 
      2. When using on-demand polling you will want use slower polling rates to reduce traffic to edge devices as on-demand polling allows you to see fast updates.
        1. Very few datapoints should be polled within 60 seconds or less, most are polled every 15 minutes or longer, or not at all.
        2. Most datapoints should not be polled.
        3. When using on-demand, you should make sure the web page is polling no more than 5 datapoints per second. If you have 30 datapoints, then the on-demand timeout max_age should be 6 seconds.
        4. When using on-demand GET request:
          1. First, the current datapoint valued stored in the SmartServer database is returned immediately for datapoints in the request.
          2. Next, the SmartServer performs a real-time poll of all device's datapoints that has a last update time longer than the specified value.
          3. When using pagination, the max_age parameter is only specified in the pg=1 request.

    2. How to see datapoint updates based on device protocol type:
      1. External LON devices  use on-demand polling, monitor rate, or event driven.
      2. Internal LON devices and internal IAP devices  defaults to events (that is, it automatically shows updates).
      3. BACnet  use on-demand polling, monitor rate, or event driven (requires COV on BACnet Device).
      4. Modbus, BACnet, IOX  use on-demand polling, need to set monitor rate.

    3. Total polling rate and logging needs to be taken into account when setting up polling or event-driven updates.  
      1. For polling, calculate the overall total polling rate for all datapoints.
        1. For example, if you are polling 30 datapoints every 60 seconds, then your overall poll rate is 0.5 polls per second.
        2. You should try to keep the Web page overall poll rate of 5 polls per second (if not logging).

    4. For example, if you have 19 datapoints
      1. If all datapoints are normal periodic polling (no max_age)
        1. poll interval = (19 / 5) + 1 = 4 seconds 
        2. max_age = -1
      2. If all datapoints are using max_age
        1. poll interval = (19 / 5) + 1 = 4 seconds 
        2. max_age = -1
      3. if you are using some datapoints that use use max_age and some that don't
        1. poll interval = (19 / 5) + 1 = 4 seconds 
          1. swap between sending GET request with max_age and without max_age (that is, at one poll interval you use the GET request with max_age, and the next without max_age)
        2. max_age = 0 for GET request with max_age

  9. If you are using any of the example web pages for your production site, then you should rename them as a new SmartServer software update may over write any changes you may make.
    1. That is, rename home1.html, login1.html, and LoginLogo1.png  to home.html, login.html and LoginLogo.png respectively.

    2. You can use the provided graphics, but if you need to change the graphics you should rename them. 

Developing Your First Web Page

Instructions on how to create a simple web page using the Simple Sensor example web page is provided in the Custom Web Page Tutorial.  This Simple Sensor example can be used as a template for creating you own custom web page.

Web Page Deployment

To access your custom web pages, you will need to replace the SmartServer IoT home web page and provide a login prompt.

  1. Create a custom web page package.
    1. You will probably want to save your custom home and login prompt:
      • /var/apollo/www/user/home.html
      • /var/apollo/www/user/login.html
      • /var/apollo/www/user/images/LoginLogo.png

    2. Save your custom web pages.

    3. It is best to create a golden image directory in which you copy the contents to the SmartServer /var/apollo/www.
      This allows you to only have to copy one directory contents to the SmartServer.

  2. Deploy to one or more SmartServers.
    1. Enable custom web pages support on each SmartServer.

    2. Copy the custom web page golden image contents into the SmartServer /var/apollo/www directory.

    3. Reboot the SmartServer.

Web Page Troubleshooting

Listed below are common web page troubleshooting tips:

  1. Use the web page development tool to identify issues during development.
    1. Tools like Visual Studio Code will show formatting issue (like missing "}" and if the catch of a try catch is missing.

  2. Look at the web browser console, which shows run-time issues.
    1. Some run-time issues show up in the console, which shows the line number of the file causing an issue.

    2. Add console.log() in your source code to see messages.

  3. Web page debugger.
    1. Most web browsers have a debugger mode that you can use to troubleshoot your web pages.

    2. Look at network traffic to see if GET requests are happening.

    3. Single-step through your code.

  4. The web page does not change in the web browser after downloading new source code onto the SmartServer.
    1. This is usually due to the web browser caching the web page data.
      Chrome may cache graphic images so if the old graphic still shows up then, then clear the browsing history.

    2. Exit all tabs and web browsers accessing this web page.

    3. Delete the web browser temporary internet files (clear browser history), exit the web browser, and then start it again.

    4. Do "a" and "b" above and then restart your computer. Sometimes even deleting the cache does not work and you also need to reboot the computer.

  5. Datapoint value does not appear in the web page.
    1. The device does not exist.

    2. The datapoint path is wrong.
      1. If in IMM mode, the datapoint path needs to include device subsystems path.
        For example, device Sensor1 could have the following datapoint path Subsystem 1.classroom1.Sensor1/Thermometer/0/temp.

    3. Check datapoint path with Datapoints widget or API tester.

  6. Datapoint value does not change.
    1. Verify value changes with Datapoints widget.

    2. If not using on-demand (max_age) for datapoint updates, then check if monitoring is enabled using the Datapoint Properties widget.

    3. If the value does not change, but you think it should, then use LonScanner Protocol Analyzer to see updates.

    4. If the value changes in Datapoint Browser widget.
      1. Verify web page tag assigned to tag.
        GET /iap/devs/*+name==Sensor1/if/LightSensor/0/nvoLuxLevel/tags/*

      2. Make sure that the datapoint pathname is correct in web page.

  7. Datapoint write does not change value on device.
    1. The SmartServer may return HTTP 204 (no content) for a PUT request whether the request was successful or not. That is, you will not get an error message if the URL or payload is incorrect. 
      1. Some write errors or warning may be reported in the write response but most other write errors or warnings show up in a WebSocket update (In the CMS Web page WebSocket updates show up as a pop up messages seen in the upper right-hand corner of the CMS Web page)
      2. If you don't use WebSockets then you can open the CMS Web page (set the Datapoint Widget polling to zero) and do a write, any write errors will show up as CMS pop up warning/error.
    2. Make sure the URL is correct and payload is properly formatted.   

    3. Use one or both of the following to see if the write PUT payload has an invalid format or the data value is invalid:
      1. ssh and issue following command (do not use the SmartServer console). Copy to notepad (or any text editor) before copying to ssh console:
               mosquitto_sub -v -t glp/0/+/ev/error 
      2. Use a MQTT tool like MQTT explorer (requires port 1883 to be open) and look at: 

    4. Use LonScanner to see if the SmartServer sent the datapoint update.

  8. After writing to a datapoint, you see the end device change but do not see a change in the web page.
    1. For many applications you write to an input datapoint and you use a corresponding output datapoint for the status.
      1. In most cases, you should see the end device input datapoint updated quickly.
      2. Seeing output updates depends on whether the SmartServer automatically gets the updates.
        1. For certain devices (like external LON devices), the SmartServer does not get automatic updates; therefore, you need to do one or more of the following:
          1. Set up monitoring (polling or event driven), add a connection or use max_age.
        2. For internal LON devices, the SmartServer gets updated automatically, so check the status (ssh to SmartServer and type "sudo supervisorctl status") to make sure the service is running.

  9. Datapoint writes show datapoint switching back and forth between old and new values on the web page (datapoint flickering).
    1. Even though writing to datapoint changes in the device almost instantaneously, the next GET request may not show the new value.
      1. It takes a finite amount of time the write value to occur. If a GET response comes in when you are writing to a datapoint then after you process the write with a new value, processing the GET response with the old value will show your html element jumping to the new value, then the old value, and eventually the new value.
      2. If you use one datapoint to write to a device and a second feedback datapoint that shows the actual state, then it can take several GET requests to see the output value change. 
    2. To reduce datapoint flicker, you may need to add a feedback delay of up to 10 seconds for this datapoint.
      1. After you write to a datapoint, ignore all datapoint updates for this datapoint for a feedback time period.