Vantiq Mobile App User’s Guide

Overview

The Vantiq mobile app is a part of Vantiq’s Realtime Collaborative System (RCS). The RCS is a network of automated Rules, Procedures and Sources that can analyze and respond to environments in real-time. Often users should be a part of the decision making network, providing data and rendering judgements about various options and recommendations. The Vantiq app provides a platform independent way to use mobile devices to gather such information from users, making them a “link in the chain” of decisions and actions.

Vantiq provides both Android and iOS implementations of the Vantiq app, which is a general purpose app to solicit information of various types. This makes use of the “push notification” capability of mobile devices; a piece of code such as a Rule or Procedure can craft a JSON object that contains a description of the user-interaction needed; this object gets sent to one or more users via the PUBLISH feature of the VAIL language. When the notification arrives on the target user’s mobile device it can be used to launch the Vantiq app which will turn the JSON description into a simple user interface which the user can respond to. The results of the interaction goes into a “response” object which becomes the payload of another Vantiq PUBLISH. A Rule can “listen” for this incoming event, extract the user-provided information and continue processing.

(It is possible for a user to initiate this process as well; see this section below.)

A series of these loops could be used to implement a complex web of both automated and human decisions and interactions, finally arriving at a target action or response.

This diagram will help visualize this process:

Overview

A Simple Example

In this simple example the process starts with a Procedure which creates a JSON object containing the Vantiq app’s instructions. It might look something like this:

PROCEDURE testApp()

var payload = {
    "responseTopic": "/a/b/c",
    "fields": [
        {
             "id": "simpleDropList",
             "type": "droplist",
             "label": "Pick your favorite color",
             "values": ["Red","Green","Blue"],
             "default": "Blue"
        }
    ]
}

var targetUsernames = ["joeuser@gmail.com"]
Notification.sendPayload("MySource", null, "Example", "Ask for my favorite color", payload, targetUsernames)

Note that the Notification.sendPayload system Procedure requires 6 arguments:

This procedure call will write the payload into the database as a record of type ArsPayloadMessage, and then use PUBLISH to send the provided Source to send a push notification to the indicated devices. The notification will signal the Vantiq app that one or more new messages can be found by doing a query against ArsPayloadMessage.

In order to send a message to a mobile app you must first define a PUSH_NOTIF Source. Go to the “Develop” / “Sources” page and click “New Source”; fill in the “Source Name” field with “MySource” and select a “Source Type” of PUSH_NOTIF. You should see a page like this:

Create MySource

If you are creating this source to target the Vantiq mobile app you should simply click the “Target Vantiq Mobile App” checkbox and then “Save” the Source. That’s all you have to do for this example.

Create Vantiq MySource

However, if you are writing your own mobile app you must register with the Google Firebase and Apple APNS services in order to send push notifications to your app on Android and iOS devices.

To target an Android app you must fill in the “Android App ID” with your app’s package name and the “Firebase Server Key” you were assigned after registering with Firebase.

To target an iOS app you must fill in the “iOS App ID” with your app’s package name and indicate whether the certificate file is targeting the “Production” or “Development (Sandbox)” servers. As part of your registration process you will have selected a PKCS12 password and created a PKCS12 certificate file; these must be entered as well. Note that since the PKCS12 certificate file is binary you must first Base64 encode it into text. For example on OSX you might use a command like this:

% openssl base64 -in cert.p12 -out outfile

The contents of the outfile can then be copied and pasted into the “PKCS12 File Contents” field.

When the Procedure runs it sends a push notification to all of the devices owned by the Vantiq user with the username “joeuser@gmail.com”. (For the device to be registered the user must simply install the Vantiq app and login to the Vantiq server; it will automatically register itself.) This means that a given user can register any number of devices of any type; when a notification is sent to a user it is broadcast to all known devices. (These registered devices are recorded in the system type ArsPushTarget. )

The main page of the app is a list of the notifications which have been received but not yet responded to:

When the user taps an item on the list it interprets the JSON instructions and produces an “input form” screen. In this case it only contains one field (the droplist) and adds a “Submit” button at the bottom:

The selected value(s) are added to a “response object” (described below) and the notification is removed from the list.

Payload Object

The “payload” JSON object that is sent with the push notification contains information needed to display the “input form” and return the results. This section will walk through the structure and meaning of the payload object.

payload.responseTopic

When the user “submits” the collected data it is sent back into the Vantiq system using the PUBLISH operation. This is essentially “raising an event” that a Rule can listen for. For that to work you must specify the “topic” that identifies the event.

The payload of this PUBLISH is the “response object” (described below) which contains all of the data entered by the user.

Topics must be of the form “/a/b/c/d”. This field is required, and there is no default value.

payload.fields

The “fields” property contains an array of “field” objects, one for each item that you wish to appear in the form. In general each item in the array of fields produces a user interface widget or “field” in the input form.

payload.state

Sometimes it may be useful to provide a field in the request object which will be passed directly through to the response. The “state” object provides a way to do that; it may be an Object, Array or any primitive type. Whatever you supply will be copied unaltered into the “state” property of the Response Object. This may be useful in correlating the request/response with some other aspect of your application.

Common Field Properties

There are certain common properties that most field objects have in common:

type

“type” is required; it indicates what kind of field is being described. Any type that does not match those enumerated below will be ignored.

Type Purpose
audio Capture a short Audio clip
barcode Scan a UPC or QRcode
buttonCluster Add a set of “submit” buttons
camera Take a photograph
checkbox Collect a Boolean value using a Checkbox
currentDateTime Return the date and time of the “submit” in ISO format
currentLocation Return the location at the time of the “submit”
date Collect an ISO date string
datetime Collect an ISO date/time string
dashboard Display a Vantiq Dashboard (no input value captured)
document Display a document (no input value captured)
droplist Select an enumerated value using a droplist
footerButton Add an “submit” button to the footer
image Display an image (no input value captured)
inlineButton Add an inline “submit” button
inputInteger Collect an integer from an “input” field
inputReal Collect an real number from an “input” field
inputString Collect a string from an “input” field
map Display a map and markers; optionally collect a location
markupImage Mark up an image
radioButtons Select an enumerated value using set of radio buttons
sectionLabel Display some text to use used as a “section” label (no input value captured)
text Display some text (no input value captured)
video Capture a short Video clip

id

“id” is required for any field type which produces input, because it is used as the property name in the “response” payload object. This name must be unique within the list of fields and must be suitable for use as a JSON property name.

label

Most fields allow you to supply an optional text label which will appear above the input widget itself, acting as a title. (In the example above the droplist has a label of “Pick your favorite color”.) If you specify a label then 4 additional “styling” fields are allowed as well: “size”, “align”, “color” and “style”. (Note that the “text” field type does nothing but show the “label” property.)

size

The font size of the text label; default to “18”.

align

The alignment of the text. This may be one of “left”, “right” or “center” and defaults to “center”.

color

The RGB color of the text (such as “#ff0000” for “red). This defaults to “#000000” (black).

style

The style of the text; this may be one of “plain”, “bold”, “italic” or “bold-italic” (defaults to “plain”).

Making fields optional

By default the user is required to enter a value for each input field. For example, if there is an “audio” field the user must record a clip or they will not be able to “submit” the results to the server. (After clicking a submit button they will see a popup warning that the clip must be recorded before the data can be sent.)

But in some cases you don’t want to require the user to supply a value; in that case most fields support some combination of the “optional” and “default” properties. There are exactly 3 use cases:

(1) You want to force the user to enter the field.

This is the default; if you don’t do anything special the user must enter data for the field before they will be allowed to “submit” to the server.

(2) You want to supply a default value

In this case you want to initialize the field with some starting value. The user can choose to just ignore the field and accept the default or override it with input of their own. (That is, once you give a field a “default” value the user is not required to change it.) The response object will contain either the default or data entered by the user.

To do this you simply add a “default” property with the value you want to be used. (Not all fields allow “default” because it’s not always practical, such as “audio” and “video” fields. This will be reflected in the documentation for each individual type of field.)

(3) You want a field to be optional but have no default

In this case you set the “optional” property on the field to “true” and do not specify a “default”, which allows the user to skip the field altogether. The initial value of the field will be left unspecified or “null”. The user is allowed to submit without specifying a value, in which case the value in the response object will be “null”. A value of “null” means “no data was entered”.

The “default” and “optional” properties are mutually exclusive; if you specify both then “optional” will be ignored. Additional details for the use of the “default” and “optional” properties for each field will appear in the descriptions below.

Field Types

This next section enumerates each of the different fields by “type”. Each field type has a different set of relevant parameters


audio field

The “audio” field allows the user to collect and submit a short audio clip.

Example:

    {
        "id": "audio1",
        "type": "audio",
        "label": "Speak your full name",
        "maxDurationSeconds": 20,
        "maxSizeK": 200,
        "placeholder": "Record the clip"
    }

The captured audio file is assigned a unique name and uploaded into an ArsDocument record in the user’s namespace (where “name” will be something like “rcs/audio/f9ceddab-add2-4b10-a602-65f82cc0a9da.m4a”). This generated name will be the “value” of the audio field returned in the response object:

    {
        "responseTopic": "/a/b/c",
        "submitValue": 0,
        "username": "joeuser@gmail.com",
        "deviceId": "75e0540bf21638bd",
        "deviceName": "HTC Desire 310",
        "values":
        {
            "audio1": "rcs/audio/f9ceddab-add2-4b10-a602-65f82cc0a9da.m4a"
        }
    }

If you want to “stream” this audio clip to another user so they can listen to it, this “name” may be used in a “document” field with flavor of “vaudio”, like this

    {
        "id": "playbackAudio1",
        "type": "document",
        "label": "Listen to the recorded audio clip",
        "flavor": "vaudio",
        "url": "rcs/audio/f9ceddab-add2-4b10-a602-65f82cc0a9da.m4a"
    }

maxDurationSeconds:integer

The maximum amount of audio to be recorded in seconds; the default is 10.

maxSizeK:integer

The maximum size of the recorded audio file in Kb; the default is 100. (Not supported for iOS.)

placeholder:string

An optional short fragment of text to display in the body of the field before the audio is recorded; the default is “Start Recording”.

optional:boolean

This field may be made optional by specifying “optional=true”; if the user doesn’t record an audio clip before submitting then “null” will be returned in the response object. See this section for additional information.


barcode field

The “barcode” field turns on the camera and scans for UPC and QRcodes. When codes are recognized they will be highlighted in the preview screen; if the user clicks one, the barcode will be converted to a string, which will be the value returned in the response object.

The “barcode” field has no special parameters.

Example:

    {
        "id": "barcode1",
        "type": "barcode",
        "placeholder": "Scan the UPC on the machine"
    }

placeholder:string

An optional short fragment of text to display in the body of the field before the scan begins; the default is “Scan Barcode”.

default:string

An optional string to be used as the assumed results of the scan. (That is, if the user does not actually scan a bar code then the “default” value will be returned in the response object as if they had.) See this section for additional information.

optional:boolean

This field may be made optional by specifying “optional=true”; if the user doesn’t scan a value then “null” will be returned in the response object. See this section for additional information.


buttonCluster field

The “buttonCluster” field is simply a set of buttons, all grouped together and appearing inline (not in the footer).

Note that “buttonCluster” is not supported on iOS.

Example:

    {
        "id": "setOfButtons",
        "type": "buttonCluster",
        "label": "Click a button",
        "values": [
            {
                "label": "Stop",
                "value": 1
            },
            {
                "label": "Go",
                "value": 2
            },
            {
                "label": "Abort",
                "value": 3
            }
        ]
    }

Each of the buttons provides a different way for the user to terminate input and send the response. The “value” for the Button clicked is included in the “submitValue” field of the response object (described below). (Note that a “buttonCluster” doesn’t really need an “id” property because it doesn’t need to return a value.)


camera field

The “camera” field allows the user to take a photograph and save it in a JPEG image.

Example:

    {
        "id": "mySelfie",
        "type": "camera",
        "placeholder": "Take snapshot"
    }

The captured JPEG is assigned a unique name and uploaded into an ArsDocument record in the user’s namespace (where “name” will be something like “rcs/image/a20ab0c1-337d-4ace-af30-3c7b9136d0be.jpg”). This generated name will be the “value” of the video field returned in the response object:

    {
        "responseTopic": "/a/b/c",
        "submitValue": 0,
        "username": "joeuser@gmail.com",
        "deviceId": "75e0540bf21638bd",
        "deviceName": "HTC Desire 310",
        "values":
        {
            "mySelfie": "rcs/image/a20ab0c1-337d-4ace-af30-3c7b9136d0be.jpg"
        }
    }

If you want to send this image to another user this “name” may be used in a “document” field with flavor of “vimage”, like this

    {
        "id": "viewJPEG1",
        "type": "document",
        "label": "View the snapshot",
        "flavor": "vimage",
        "url": "rcs/image/a20ab0c1-337d-4ace-af30-3c7b9136d0be.jpg"
    }

placeholder:string

An optional short fragment of text to display in the body of the field before the photo is taken; the default is “Take Photo”.

optional:boolean

This field may be made optional by specifying “optional=true”; if the user doesn’t take a photo before submitting then “null” will be returned in the response object. See this section for additional information.


checkbox field

The “checkbox” field produces a classic checkbox which can be used to collect a boolean value (true or false).

Example:

    {
        "id": "cb",
        "type": "checkbox",
        "checkboxLabel": "Check Me",
        "default": true
    }

default:boolean

The default setting of the checkbox, “true” or “false” (i.e. “checked” or “unchecked”). This property is optional and defaults to “false”.

“checkbox” fields are unusual in that they are always treated as if they are optional; the user can either leave the default setting as-is or toggle it, but they are never required to touch it.

checkboxLabel:string

The text label that should appear as part of the checkbox; default is “” (i.e. the “empty string”).


currentDateTime field

This field does not actually create any UI elements that the user can see or interact with; it simply creates a item in the response the contains the ISODate indicating the date and time when the response was submitted.

The “currentDateTime” field has no special parameters.

Example:

    {
        "id": "now",
        "type": "currentDateTime"
    }

currentLocation field

This field does not actually create any UI elements that the user can see or interact with; it simply creates a item in the response the contains the location of the mobile device at the time the response was submitted. This response is simply a JSON object with the “longitude” and “latitude” properties.

The “currentDateTime” field has no special parameters.

Example:

    {
        "id": "here",
        "type": "currentLocation"
    }

date and datetime field

The “date” and “datetime” fields are similar; both ask the user to enter an arbitrary date (or date and time) using a “chooser” widget.

Examples:

{
    "id": "timeOfBirth",
    "type": "datetime",
    "label": "When was your birth day and time?",
    "default": "1991-04-20T09:30-07:00"
}
{
    "id": "birthDate",
    "type": "date",
    "label": "When was your birthday?",
    "default": "1991-04-20"
}

default:string

An optional string in ISODate format with the default value for the date/time chooser shown to the user. See this section for additional information.

optional:boolean

This field may be made optional by specifying “optional=true”; if the user doesn’t enter a value then “null” will be returned in the response object. See this section for additional information.


dashboard field

The “dashboard” field does not produce any input from the user; it simply allows the user to a Vantiq “Dashboard”.

Examples:

    {
        "type": "dashboard",
        "label": "View my Dashboard",
        "startTab": "Graph One"
    }

startTab:string

If specified this allows you to specify which Dashboard tab should be selected (by supplying the tabs “label”)*[]:

placeholder:string

An optional short fragment of text to display in the body of the field before the Dashboard is launched; the default is “View the Dashboard”.


document field

The “document” field does not produce any input from the user; it simply allows the user to view a page or document corresponding to the supplied URL. This is usually done by launching a special app or Web Viewer that takes over the screen and displays the document.

Examples:

{
    "type": "document",
    "label": "View a PDF Document",
    "flavor": "pdf",
    "url": "http://www.myhost.com/InstructionManual.pdf",
    "placeholder": "View it"
}
{
    "type": "document",
    "label": "View an HTML Document",
    "flavor": "html",
    "url": "https://www.google.com",
    "placeholder": "Show me"
}

flavor:string

This property is optional; if supplied it must be one of the following types:

The “vaudio”, “vimage” and “vvideo” flavors are used to listen, view or stream media which have been previously captured using the “audio”, “camera” and “video” fields; refer to each field type for details.

url:string

This property is required and is a URL which points to the document to be displayed.

placeholder:string

An optional short fragment of text to display in the body of the field before the document is loaded; the default is “View the PDF document” or “View the Web document” depending on the “flavor”.


droplist field

This field can be used to display a classic “drop-down list” to show and edit an enumerated value. (This is structurally identical to the “radioButtons” field described below.)

values:array

This property is required; it contains an array enumerating the values to be available in the dropdown list. These can be provided in two different formats. The first is a simple array of Strings:

    {
        "id": "simpleDropList",
        "type": "droplist",
        "label": "Pick a color (simple)",
        "values": ["Red","Green","Blue"],
        "default": "Blue"
    }

This works for many use cases, but sometimes it is more convenient to specify a separate value for the “label” shown and the “value” returned in the response. For example:

    {
        "id": "complexDropList",
        "type": "droplist",
        "label": "Pick a color (complex)",
        "values": [
            {
                "label": "Red",
                "value": 1
            },
            {
                "label": "Green",
                "value": 2
            },
            {
                "label": "Blue",
                "value": 3
            }
        ],
        "default": 2
    }

default:depends

This property is optional; it specifies which of the enumerated values should be initially selected. (Obviously it must exactly match one of the values in the list.) The datatype of the “default” value depends on which form of the “values” property you used. If you used the simple form then the “default” must be a string which matches one of the elements in the “values” array. If you used the complex form then “default” must exactly match one of the supplied “value” elements, which could be a string or number.

See this section for additional information.

optional:boolean

This field may be made optional by specifying “optional=true”; if so a dummy “null” item will be inserted at the front of the list which tells the user they may select a value. If the user doesn’t enter a value then “null” will be returned in the response object. See this section for additional information.


footerButton field

The “footerButton” field adds a button to the footer at the bottom the input page. When the button is clicked the data that has been entered will be published back to the server in the “response object” (described below). The page will close, the app will return to the list of pending notifications and the submitted notification will be removed from the list.

Note that “footerButtons” don’t really need “id” properties because they don’t return a value.

If no “inlineButton” fields or “footerButtons” were specifed then the app will automatically provide a “Submit” footer button at the bottom of the page. (This is so there will always be a least one button available.

Example:

    {
        "type": "footerButton",
        "buttonLabel": "Stop",
        "value": 100
    }

buttonLabel:string

This property is required and indicates the text shown by the button.

value:integer

This value is required; it specifies a unique number identifying the button so the code that processes the response object can tell which button was used.


image field

This property allow you to display an image to the user; it does not allow for any user input to be returned. A small version of the image will be displayed “inline”; if the user taps the image it will be shown on a separate page where it can be zoomed and panned using the usual gestures.

Example:

    {
        "id": "kitty",
        "type": "image",
        "label": "My Cat",
        "size": 40,
        "align": "center",
        "url": "https://pixabay.com/static/uploads/photo/2014/03/29/09/17/cat-300572_960_720.jpg"
    }

url:string

This property is required and is a URL which points to the image to be displayed.


inlineButton field

The “inlineButton” field adds a customized button inside the input form. When the button is clicked the data that has been entered will be published back to the server in the “response object” (described below). The page will close, the app will return to the list of pending notifications and the submitted notification will be removed from the list.

Note that “inlineButtons” don’t really need “id” properties because they don’t return a value. They accept some optional properties to visually style the buttons.

If no “inlineButton” fields or “footerButtons” were specifed then the app will automatically provide a “Submit” footer button at the bottom of the page. (This is so there will always be a least one button available.

Example:

    {
        "type": "inlineButton",
        "buttonLabel": "Stop",
        "buttonLabelSize": 40,
        "buttonLabelColor": "#ffffff",
        "buttonBackgroundColor": "#ff0000",
        "value": 100
    }

buttonLabel:string

This property is required and indicates the text shown by the button.

buttonLabelSize:string

Similar to the “size” property used with “labels”, this specifies the font size of the button label; default to “18”.

buttonLabelStyle:string

Similar to the “style” property used with “labels”, this specifies the style of the button label; this may be one of “plain”, “bold”, “italic” or “bold-italic” (defaults to “plain”).

buttonLabelColor:string

Similar to the “color” property used with “labels”, this specifies the RGB color of the button label (such as “#ff0000” for “red). This defaults to “#d0d0d0” (grey).

buttonBackgroundColor:string

This property is optional and specifies the RGB color of the button background (such as “#ff0000” for “red). This defaults to “#000000” (black).

value:integer

This value is required; it specifies a unique number identifying the button so the code that processes the response object can tell which button was used.


inputInteger, inputReal fields

The inputInteger and inputReal fields are similar, both enabling the user to enter a number. (Obviously one is for integers and one for reals.) The number must always lie within an indicated range.

There are two “flavors” of these fields; the user can tap a number into a text input field or be shown a numeric “slider” which can be used to select number in the valid range.

Examples:

{
    "id": "input1",
    "type": "inputInteger",
    "label": "Enter an Integer",
    "default": 0,
    "placeholder": "A Hint",
    "minValue": -10,
    "maxValue": 20
}
{
    "id": "input2",
    "type": "inputInteger",
    "label": "Enter an Integer (Slider)",
    "flavor": "slider",
    "default": 0,
    "minValue": -10,
    "maxValue": 20
}
{
    "id": "input3",
    "type": "inputReal",
    "label": "Enter a Number",
    "default": 0,
    "placeholder": "Hint",
    "minValue": -10.0,
    "maxValue": 20.0,
    "units": "ms"
}
{
    "id": "input4",
    "type": "inputReal",
    "label": "Enter a Number (Slider)",
    "flavor": "slider",
    "default": 0,
    "minValue": -10.0,
    "maxValue": 20.0,
    "units": "ms"
}

flavor:string

This property is optional and must be one of “slider” or “text”; the default is “text”. This controls which kind of widget is shown to the user.

minValue:number

This property should always be specified since it indicates the minimum allowed value. (It defaults to 0 if omitted.) Obviously “minValue” must always be less than “maxValue”.

maxValue:number

This property should always be specified since it indicates the maximum allowed value. (It defaults to 100 if omitted.) Obviously “minValue” must always be less than “maxValue”.

units:string

This property is optional and only applies to the “text” input flavor (it is ignored for “sliders”). It provides a fragment of text to be shown to the right of the input field which would be used to tell the user the units of the supplied value (e.g. “seconds” or “meters”). If omitted this defaults to the empty string and no “units” value is shown.

placeholder:string

This property is optional and only applies to the “text” input flavor (it is ignored for “sliders”). It provides a fragment of text to be used as the “placeholder” or “hint” within the input field. This value only appears if the field is empty. If omitted this defaults to the empty string and no “placeholder” value is shown.

default:number

This property is optional and can be used to supply the default value that the field should contain. If supplied it must be within the valid range. If omitted the default value will be taken from “minValue” for “sliders” but will be the empty string for flavor “text”. See this section for additional information.

optional:boolean

This property is ignored if “flavor” is “slider”.

If “flavor” is “text” and “optional” is “true” then the user can either leave the field empty or supply a valid numeric value. If the user doesn’t enter a value then “null” will be returned in the response object. See this section for additional information.


inputString field

This field allows the user to enter a string in a standard text input field.

Example:

    {
        "id": "yourName",
        "type": "inputString",
        "label": "Enter your name",
        "placeholder": "Your name here"
    }

placeholder:string

This property is optional; it provides a fragment of text to be used as the “placeholder” or “hint” within the input field. This value only appears if the field is empty. If omitted this defaults to the empty string and no “placeholder” value is shown.

default:string

An optional string with the default value that should appear in the input field. See this section for additional information.

optional:boolean

This field may be made optional by specifying “optional=true”; the input field will be empty and if the user doesn’t enter a value then “null” will be returned in the response object. See this section for additional information.


map field

This field can be used to display a map to the user at a given location; you may optionally display a set of “markers” or “pins”. If can also be used to allow the user to click on a map location to set a pin of their own; this location would appear in the “response” object for this field. (Note that if you want the map to be “readonly” so the user can’t create their own marker you can simply omit the “id” property from the map field; since there is no way to return a value the user clicks will be ignored.))

Note that the calculation of “center point” gets a little more complicated if you specify markers. When markers are provided the map is initially positioned and zoomed to neatly frame the markers. The “location” is treated as an additional “hidden marker” if you provided one, so that all the points you specified will be “in frame”.

Example:

    {
        "id": "myFavoriteRide",
        "type": "map",
        "label": "Disneyland",
        "location": {
            "longitude": -117.918974,
            "latitude": 33.812092
        },
        "markers": [
                    {"label": "Space Mountain", "longitude": -117.917193, "latitude": 33.811379},
                    {"label": "Haunted Mansion", "longitude": -117.922675, "latitude": 33.811530 }
        ]
    }

location:object

This property is optional and indicates the initial center point of the map. (If you specified markers then “location” is treated as if was just another invisible marker point.) It can be supplied as a GeoJSON object or an object with “longitude” and “latitude” properties:

    // GeoJSON
    {"type": "Point", "coordinates": [-117.918974, 33.812092]}

    // Simple
    {"longitude":-117.918974,"latitude":33.812092}

If omitted (and there are no markers) the current location is used as the center point.

markers:array of objects

This property is optional and can be used to specify a list of “markers” or “pins” to display on the map:

    {
        "id": "dland",
        "type": "map",
        "label": "DisneyLand",
        "location": {"longitude":-117.918974,"latitude":33.812092},
        "markers": [
            {"label": "Space Mountain","longitude":-117.917193,"latitude":33.811379},
            {"label": "Haunted Mansion","longitude":-117.922675,"latitude":33.811530}
        ],
        "placeholder": "Show it"
    }

In addition to “label”, “longitude” and “latitude” each marker may optionally contain a “color” property which indicates the color of the marker. (The default is “red”.) The “color” contains the HSV “hue” and may be a number from 0 to 359 or one of the following equivalent color names:

placeholder:string

An optional short fragment of text to display in the body of the field before the map is shown; the default is “View the map and select a location” or “View the map” depending on whether or not an “id” was provided and input is expected).

maptype:string

The “maptype” property is optional and must be one of “standard”, “satellite” or “hybrid”. This will specify the type of map which will be displayed.

minMapWidth:number

By default when you specify a set of markers the map will zoom the camera such that all the marker points will be visible (plus an extra 50 pixels for padding). In some cases (such as a small number of points which are close together) you may wish to specify that the map is always zoomed out to some minimum width for more context. The “minMapWidth” property can be used to specify the minimum width of the map viewport in meters.

default:object

This property is optional and can be used to supply the default “clicked location” value that the field should contain.

It can be supplied as a GeoJSON object or an object with “longitude” and “latitude” properties:

    // GeoJSON
    {"type": "Point", "coordinates": [-117.918974, 33.812092]}

    // Simple
    {"longitude":-117.918974,"latitude":33.812092}

See this section for additional information.

optional:boolean

This field may be made optional by specifying “optional=true”; if the user doesn’t click the map to specify a location then “null” will be returned in the response object. See this section for additional information.


markupImage field

The “markupImage” field allows the user to do some simple “paintbrush” drawing over an existing image. (In general this would be used to let a user call attention to some feature of the image, perhaps by drawing circles or arrows.) These may either be existing images (from the web or from a Vantiq document) or an image snapped with the camera.

Example:

    {
        "id": "myMarkedUpImage",
        "type": "markupImage",
        "source": "camera"
    }

The edited image is saved as a JPEG with a unique name and uploaded into an ArsDocument record in the user’s namespace (where “name” will be something like “rcs/image/a20ab0c1-337d-4ace-af30-3c7b9136d0be.jpg”). This generated name will be the “value” of the markupImage field returned in the response object:

    {
        "responseTopic": "/a/b/c",
        "submitValue": 0,
        "username": "joeuser@gmail.com",
        "deviceId": "75e0540bf21638bd",
        "deviceName": "HTC Desire 310",
        "values":
        {
            "myMarkedUpImage": "rcs/image/a20ab0c1-337d-4ace-af30-3c7b9136d0be.jpg"
        }
    }

If you want to send this image to another user this “name” may be used in a “document” field with flavor of “vimage”, like this

    {
        "id": "viewJPEG1",
        "type": "document",
        "label": "View the snapshot",
        "flavor": "vimage",
        "url": "rcs/image/a20ab0c1-337d-4ace-af30-3c7b9136d0be.jpg"
    }

placeholder:string

An optional short fragment of text to display in the body of the field image is edited; the default is “Mark up an image” or “Take a photo and mark it up”.

optional:boolean

This field may be made optional by specifying “optional=true”; if the user doesn’t edit the image before submitting then “null” will be returned in the response object. See this section for additional information.

source:string

The image source can be specified in one of 3 ways:


radioButtons field

This field can be used to display a set of classic “radio buttons” to show and edit an enumerated value. (This is structurally identical to the “droplist” field described above.)

values:array

This property is required; it contains an array enumerating the values to be available in the list of radio buttons. These can be provided in two different formats. The first is a simple array of Strings:

    {
        "id": "simplwRadioButtons",
        "type": "radioButtons",
        "label": "Pick a color (simple)",
        "values": ["Red","Green","Blue"],
        "default": "Blue"
    }

This works for many use cases, but sometimes it is more convenient to specify a separate value for the “label” shown and the “value” returned in the response. For example:

   {
        "id": "complexRadioButtons",
        "type": "radioButtons",
        "label": "Pick a color (complex)",
        "values": [
            {
                "label": "Red",
                "value": 1
            },
            {
                "label": "Green",
                "value": 2
            },
            {
                "label": "Blue",
                "value": 3
            }
        ],
        "default": 2
    }

default:depends

This property is optional; it specifies which of the enumerated values should be initially selected. (Obviously it must exactly match one of the values in the list.) The datatype of the “default” value depends on which form of the “values” property you used. If you used the simple form then the “default” must be a string which matches one of the elements in the “values” array. If you used the complex form then “default” must exactly match one of the supplied “value” elements, which could be a string or number.

See this section for additional information.

optional:boolean

This field may be made optional by specifying “optional=true”; if the user doesn’t enter a value then “null” will be returned in the response object. See this section for additional information.


sectionLabel field

This field is simply a way to add static text to the display; the text is given a predefined style that makes it suitable for use as a highlighted “section label” that describes a set of fields which follow. (That is, the user cannot use it to produce any input.) The “sectionLabel” field ignores the 4 “styling properties” (“size”, “color”, “align” and “style”).

Example:

    {
        "type": "sectionLabel",
        "label": "Important Section",
    }

text field

This field is simply a way to add static text to the display; the user cannot use it to produce any input. The “text” field shows nothing but the “label”. (The 4 “styling properties” (“size”, “color”, “align” and “style”) apply to the text in the usual way.)

Example:

    {
        "type": "text",
        "label": "Hello, World!",
        "size": 40,
        "color": "#00ff00"
    }

video field

The “video” field allows the user to collect and submit a short video clip.

Example:

    {
        "id": "video1",
        "type": "video1",
        "label": "Record a video clip of your surroundings",
        "maxDurationSeconds": 20,
        "maxSizeK": 2000,
        "placeholder": "Begin"
    }

The captured video file is assigned a unique name and uploaded into an ArsDocument record in the user’s namespace (where “name” will be something like “rcs/video/15879441-7910-445e-81e6-fd91a2a7d28e.mp4”). This generated name will be the “value” of the video field returned in the response object:

    {
        "responseTopic": "/a/b/c",
        "submitValue": 0,
        "username": "joeuser@gmail.com",
        "deviceId": "75e0540bf21638bd",
        "deviceName": "HTC Desire 310",
        "values":
        {
            "video1": "rcs/video/15879441-7910-445e-81e6-fd91a2a7d28e.mp4"
        }
    }

If you want to “stream” this video clip to another user for playback this “name” may be used in a “document” field with flavor of “vvideo”, like this

    {
        "id": "playbackVideo1",
        "type": "document",
        "label": "Play back the recorded video clip",
        "flavor": "vvideo",
        "url": "rcs/video/15879441-7910-445e-81e6-fd91a2a7d28e.mp4"
    }

maxDurationSeconds:integer

The maximum amount of video to be recorded in seconds; the default is 10.

maxSizeK:integer

The maximum size of the recorded video file in Kb; the default is 1000 (1MB). (Not supported for iOS.)

placeholder:string

An optional short fragment of text to display in the body of the field before the video recording begins; the default is “Start Recording”.

optional:boolean

This field may be made optional by specifying “optional=true”; if the user doesn’t record a video clip before submitting then “null” will be returned in the response object. See this section for additional information.

Response Object

When the user submits the data (and all the data is validated) then the app creates a “response object” which contains all the submitted data and PUBLISHes it to the Vantiq system. The format is simple; for the example given above it would look something like this:

    {
        "responseTopic": "/a/b/c",
        "submitValue": 0,
        "username": "joeuser@gmail.com",
        "deviceId": "75e0540bf21638bd",
        "deviceName": "HTC Desire 310",
        "values":
        {
            "simpleDropList": "Green"
        },
        "state": {"myStateData":123}
    }

The responseTopic property contains the same value that was in the original payload.

The “submitValue” is the “value” of the button that was clicked to submit the form. (If you did not specify any “button” or “buttonCluster” fields of your own then the user clicked the automatically generated “Submit” button, which always returns the value “0”.)

“username” is the username of the responder (i.e. the name they logged in with).

“deviceId” is a token that uniquely identifies the mobile device.

“deviceName” is some kind if human-readable string that defines the device.

The “values” property contains an object with one property for each “field” that produced input and contained an “id”.

The “state” property will appear if you specified “state” in the request object; its value will be passed through unmodified. This may be useful in correlating the request/response with some other aspect of your application.

(Note that “username”, “deviceId” and “deviceName” will match the corresponding properties in a record of type ArsPushTarget. Records of this type are used to manage all the devices which have logged in to the Vantiq system and registered themselves as push notification targets.)

Direct and Indirect Payloads

If you choose to send a “payload” to your mobile devices without using Notification.sendPayload you could use PUBLISH to send a message directly using an “inline” payload like this:

PROCEDURE getMyFavoriteDirectly()

var payload = {
    responseTopic: "/a/b/c",
    fields: [
        {
             id: "simpleDropList",
             type: "droplist",
             label: "Pick your favorite color",
             values: [ "Red", "Green", "Blue" ],
             default: "Blue"
        }
    ]
}

PUBLISH { title: "Example", 
           body: "Ask for my favorite color",
           data: payload } TO SOURCE MySource USING { to: [ "joeuser@gmail.com" ] }

Using this “direct” technique your payload is not written into ArsPayloadMessage; it simply gets sent inside the push notification message itself.

Unfortunately push notification schemes such as APNS (for iOS) and Firebase (for Android) have a built-in limitation on how large a message they can send to a mobile device (usually around 2K). If you try to send a payload directly it is not too difficult to exceed this limit. This is where the system Procedure Notification.sendPayload comes in; it will save your payload as an instance of the Type ArsPayloadMessage, and then send a much smaller message to the mobile device using Push notifications, containing only enough information that the mobile app can query ArsPayloadMessage for the full payload. (This procedure has 6 arguments, described above.) All of the payloads you send this way are “indirect” in that the messages aren’t sent directly to the device.

Using the Notification.sendPayload Procedure looks like this:

PROCEDURE getMyFavoriteUsingSendPayload()
var payload = {
    responseTopic: "/a/b/c",
    fields: [
        {
             id: "simpleDropList",
             type: "droplist",
             label: "Pick your favorite color",
             values: [ "Red", "Green", "Blue" ],
             default: "Blue"
        }
    ]
}

var targetUsernames = [ "joeuser@gmail.com" ]
Notification.sendPayload("MySource", null, "Example", "Ask for my favorite color", payload, targetUsernames)

But there is another “indirect” technique that can also be used to avoid the 2K limit, and there are times when you might wish to use it. This requires first saving your payload as a unique named instance of the ArsRCSPayload system Type, and send only the name of this object rather than the actual payload itself. The instance would look something like this:

    {
        "name": "GetMyFavoriteColor",
        "payload": {
            "responseTopic": "/a/b/c",
            "fields": [
                {
                     "id": "simpleDropList",
                     "type": "droplist",
                     "label": "Pick your favorite color",
                     "values": ["Red","Green","Blue"],
                     "default": "Blue"
                }
            ]
        }
    }

When doing the actual PUBLISH at runtime you would remove the “fields” array property and reference the ArsRCSPayload object by name like this:

PROCEDURE getMyFavoriteIndirectly()  

var payload = {
    responseTopic: "/a/b/c",
    payloadName: "GetMyFavoriteColor"
}

PUBLISH { title: "Example", 
           body: "Ask for my favorite color", 
           data: payload } TO SOURCE MySource USING { to: [ "joeuser@gmail.com" ] }

When the indirect payload notification is received the Vantiq mobile app will load the actual payload object directly from the server and continue as if the “fields” had been inside the request.

There are several reasons why you might want to do this:

Avoiding Size Limitations

First (and most importantly) is that the Android and iOS “push notifications” impose an arbitrary limit on the size of the payload they can carry (usually around 2K). If your JSON payload exceeds that size, the notification will fail. As a workaround, you can save the payload in an ArsRCSPayload object and just reference it in the payload object by name. This will keep the payload well below any size limitations. (Of course, using the Notification.sendPayload procedure avoids this pitfall as well.)

Reusing payloads

You may also find that you want to issue the same notification/payload from more than one Rule or Procedure. Rather than duplicating (and maintaining) the same payload object in multiple places they can all just reference this same common copy.

Overriding a common payload

In this case you might wish to create a common payload that is shared by various Rules and Procedures, but which will override or augment the same basic payload.

For example, at runtime a Procedure might SELECT an instance of ArsRCSPayload into memory and then modify the “fields” array, either adding additional items or modifying the existing ones (perhaps with different “default” values). The modified payload could then be sent using Notification.sendPayload (or a direct PUBLISH if small enough).

Creating Indirect Payloads

The most brute-force way to create an indirect payload is to use the Developer Portal or CLI to “manually” add an instance of ArsRCSPayload. You only need to set two properties, a unique “name” and the actual payload in property “payload”.

A much easier approach is to use the “RCS Pages” feature of the Developer Portal; this allows you to construct a payload visually instead of typing in JSON by hand. (Use the “New Payload” button to use the visual editor to create and save a payload instance.) Of course this tool can also be used to edit existing instances of ArsRCSPayload.

ArsRCSRequest Objects

Normally the Vantiq Mobile App is a vehicle for sending Notifications to users to solicit some response data (described by the “payload” fields). But there are times when you want a user to be able initiate the sending of data rather than respond to a request from a Rule or Procedure. You can build a “library” of such user-initiated response payloads which will appear in the “Start” tab of the mobile app.

The “RCS Pages” editor in the Dev Portal allows you to create and edit ArsRCSRequest objects for this purpose. In addition to the “fields” that make up the data input portion you must also specify the “Title”, “Body” (i.e. subtitle) and “Response Topic” that will be used for the item that appears in the “Start” section. The user can navigate to this list, launch one of the pre-built pages, fill in the data and publish it to the system.

Alternatives to Notification.sendPayload

As described above the Notification.sendPayload Procedure allows you send a notification (and an associated payload) to a list of users in your namespace. There are two other ways to designate the target list of users:

Notification.sendPayloadToGroups

This variation allows you to target groups instead of individual users. The member list of each group will be used to create the actual list of target users. (Duplicate users are automatically removed.) The parameters are similar to Notification.sendPayload:

Notification.sendPayloadToAll

This variation allows you to target all the users in your namespace (including the sender). The parameters are similar to Notification.sendPayload: