Skip to content

Instantly share code, notes, and snippets.

@accuware accuware/dragonfly2java_1.3.md Secret
Last active Jul 11, 2019

Embed
What would you like to do?
Dragonfly 2 Java, version 1.3

Version 1.3 feature table

Feature Supported
Java standalone app, available as obfuscated JAR
USB, internal or external camera support
Web server and REST interface for control and status
SSL support
GZIP support
Local map save and load
Local map update and delete
Configuration read/write available via REST
Map synchronisation
Support for camera capture, native, mono and stereo
Offline map display
Position upload, history, custom server
Position logging to CSV
Local video recording
Support for virtual markers
Support for plain X, Y and Z display
Support for pitch, yaw, roll and rotation matrix
Support for version update check
Support for metric coordinates
Mapppoint API

Functions of the Java app

The Java app, controlled and monitored by this dashboard, makes use of an internal or external camera and feeds the captured images to native code, which finally enables it to determine the position of the device and to 3D-map the environment.

Because 3D-Mapping is one of the central tasks of the Java app and the item "map" or "mapping" is all the way used in this documentation, here a short primer regarding "What is a map?" in the context of Dragonfly:

A map is the virtual representation of what has been already seen by Dragonfly. It corresponds to a file, that stores all the information describing a visual environment and enables the tracking of the positions of a camera fitted device in this environment later on, hence "no map, no positioning".

A map contains:

  • A store of all the markers that have previously been detected with their position, printed markes as well as virtual markers (reference points, see below)
  • All the 3D points corresponding to the 3D reconstruction of the environment
  • All the features that have been detected, together with a visual representation of these features

Even though the dashboard is fully capable of loading, storing and manipulating those maps from a local, non-Internet connected environment, there is a special branch of the dashboard responsible for synchronising maps with a central repository hosted at Accuware. This enables collaborative work between different parties on the maps. Please refer to Map Synchronisation for details on how the synchronisation process is working and what basic principles apply.

The Java app exposes a Web server interface on a configurable port and a REST API for remote control. It also hosts a dashboard.

A word about markers.

Markers are an important part of the positioning process. They help in determining the relation of the internally used virtual coordinates to the coordinate system of the "real" world.

Markers can be made known to the system in two different ways:

  • In the form of printed visual markers (aka real markers), which are permanently installed at previously defined coordinates and recognized at runtime.
  • In the form of manually fixed reference points (aka virtual markers), which are transmitted via this dashboard to the Dragonfly Java App exactly at the time when the device is at this point.

For the first method the Accuware Dashboard provides a page, which helps you to create, configure and print the markers (https://dashboard.accuware.com/#dragonfly/marking).

In case, placing printed visual markers is not an option, you can alternatively pin-point the current location of the device live on the floor plan. Check out the Quick help given on the Map calibration tab of this dashboard for details.

In any way, these two methods have to be applied only once in the entire mapping process for a level.

Functions of the dashboard

The dashboard you are currently using is a ReactJS static web app hosted by the Java app. It is providing currently four tabs

  • Main
  • Maps
  • Configuration
  • Documentation

The app makes use of the REST API, also hosted by the Java app. It generally provides all functionality available via REST plus means to fetch and use floor plans.

Even though web based, the app itself does not necessarily need to have Internet connectivity. This applies with the exception of the initialization of the floor plan display as described below.

The Main tab shows a tabular overview of status parameters obtained using the Get status API. Additionally it allows to start/stop a mapping and/or positioning. It displays the position on a floor plan view. If the site has floor plans, it downloads, caches and displays it, together with available geofence information, if appropriate location and level information is provided by the core. It uses the site username and password information provided in configuration. Whenever Internet is available, the app checks for fresh floor plan and geofences in the Accuware cloud. Generally an Internet connection is at least required once in order to download and cache floor plans and geofences. Additionally means to pin-point real-time positions on floor plans are provided.

The Map tab allows to load, save, reset, update, delete local maps and sync local maps with the remote server. Maps are the results of the 3D mapping of the visual environment.

The Configuration tab provides means to configure the Java app. Other utility functions are offered.

The Documentation tab contains this documentation.

If default parameters are applied, the dashboard is available at http://localhost:5000. No authentication required. The webserver supports SSL. In case you have a valid certificate, please provide the path to WEBSERVER_KEYSTORE_FILE and WEBSERVER_KEYSTORE_PASSWORD (best encrypted) in ./config/dragonfly2.properties and set WEBSERVER_SSL_SUPPORTED to true.

Note: The use of self-signed server certificates requires each curl REST API call to be decorated with the extra parameter -k in order to make curl accepting the certificate. Ex: curl https://localhost:5000/api/v1/config -k.

Start of the Java app

In a terminal window:

java -jar -Djava.library.path="." Dragonfly2Java.jar

The app is logging to console and to a daily rolling log file in ./logs.

Configuration of the Java app

Configuration can be provided by either a Java property file (./config/dragonfly2.properties) or the dashboard, page "Configuration".

The configuration file does not necessarily have to be available at very first startup. Mandatory parameters will be determined in dialog with user and file will be created. There are currently only two mandatory parameters, listed first below.

Configuration Item Type Meaning Default
SITE_ID String MANDATORY Accuware Site ID n.a.
SITE_USERNAME String MANDATORY Accuware Site Username n.a.
SITE_PASSWORD String Accuware Site Password (unencrypted or encrypted), see "Encrypt string" n.a.
WEBSERVER_PORT Integer Local web server port 5000
WEBSERVER_SSL_SUPPORTED Boolean Local web server SSL supported (requires WEBSERVER_KEYSTORE_FILE and WEBSERVER_KEYSTORE_PASSWORD) false
WEBSERVER_KEYSTORE_FILE String Path to keystore.jks file n.a.
WEBSERVER_KEYSTORE_PASSWORD String Password for keystore.jks file (unencrypted or encrypted), see "Encrypt string" n.a.
WEBSERVER_WEBSOCKET_ENABLED Boolean Enables use of status pushes via web socket true
LOG_LEVEL Integer Controls granularity of logging. 0: off, 1: fatal, 2: error, 3: warn, 4: info, 5: debug, 6: trace, 7: all 7
JMX_REMOTE_MONITORING_ENABLED Boolean Enables monitoring via JConsole. Authoritzation/Authentication taken from files ./config/jmx_access and ./config/jmx_password false
JMX_RMI_REGISTRY_PORT Integer JMX registry port, required to form the JMX Service URL 33985
JMX_RMI_SERVER_PORT Integer JMX server port, required to form the JMX Service URL 33986
AUDIBLE_STATUS_ENABLED Boolean Gives audible feedback on status changes and marker detection true
CAM_MODE String Controls, in which mode the camera(s) should be operated, "mono" or "stereo" "mono"
CAM_SOURCE String GStreamer pipe definition, FFMPEG parameter, index or list of comma separated indexes. Default -1 (default camera) (see "CAM_SOURCE explained"). "-1"
CAM_PREVIEW_OPTION Integer Visible feedback of the image processing. 0: off, 1: in Javascript (websockets must be enabled), 2: in Java, 3: in Javascript and Java (just for completeness) 1
CAM_FOV Number Programmatically rectify the image and set a custom field-of-view. Value should be above 0 and below the actual FOV of the camera (max 180). Default 0 (not applied) 0f
CAM_IMAGE_WIDTH Integer Camera capture and preview image width 640
CAM_IMAGE_HEIGHT Integer Camera capture and preview image height 480
CAM_CALIBRATION_FILE String Filename of the JSON camera calibration params file, created by CalibrationNative app, located in ./config ""
MAP_CALIBRATION_METHOD Integer Number of markers required to be detected, either 0 or 3. If you are using printed or virtual markers, the number has to be 3. If you configuring 0, positions are displayed in Direct view only, w/o any geo-reference. 3
POSITION_UPLOAD_INTERVAL Integer Number of milliseconds between two consequtive uploads of positions to the Accuware Dashboard (for tracking for deviceId 0
POSITION_UPLOAD_STORE Boolean Controls, if uploaded positions will be stored in the Accuware Cloud false
POSITION_LOG_ENABLED Boolean Controls, if positions should be saved locally (daily rolling CSV log './logs/positionlog.csv', see CSV logging) false
VIDEO_RECORDING_ENABLED Boolean Controls, if the video taken from the camera(s) should be stored locally, folder './recorded', grouped by siteId false
VPS_SERVER_URL String Allows you to overwrite the VPS server URL (Note: provide the entire initial path as shown in default) https://cvnav.accuware.com/api/v1

Note: Camera calibration is a procedure to improve the accuracy of positioning results and mandatory for stereo cameras. For obtaining information about how to calibrate stereo cameras please consult Accuware Support. The calibration of a monocular camera can be done using the Accuware Dragonfly Demo on the web. Whereas in CAM_MODE "mono" it is allowed to start positioning w/o configured calibration file, a start is rejected in CAM_MODE "stereo" . The VPS_SERVER_URL is a private configuration parameter of the Java property file (./config/dragonfly2.properties). It is not available for modifications via the JS GUI.

Startup behaviour clarified

If after startup the Java app detects, that there is no Java property file (./config/dragonfly2.properties), it usually presents an entry form, in which SITE_ID and SITE_USERNAME - the only mandatory parameters - are obtained in order to enable the error free start of the app. If a SITE_PASSWORD is available, it can be entered here too. All credentials are immediately validated against the Accuware Dragonfly Cloud. Validated credentials allow you to use the app for a certain amount of time without the need for an Internet connection. If you don't have credentials, you can directly signup from this form for a time limited demo account.

Valid credentials are also required in order to perform the initial download of metadata like floor plans and defined geo fences from the Accuware Dragonfly Cloud.

Note: A validation error of any kind is immediately reported, so that you will not be able to launch the app with invalid credentials. That in turn means, that your initial start of the Java application unconditionally requires an active Internet connection.

Once the online validation has been passed, the initial ./config/dragonfly2.properties is written to disk and the Java app launches a GUI automatically into your default browser at localhost:5000.

Since this credential input form might not be accessible in headless installations, it is possible to provide a handful of important startup parameters in System.properties via command line parameters.

Those are:

Parameter Meaning
siteId see SITE_ID
login see SITE_USERNAME
password see SITE_PASSWORD, accepted as unencrypted or encrypted string, see "Encrypt string"
webServerPort see WEBSERVER_PORT
vpsServerUrl see VPS_SERVER_URL
logLevel see LOG_LEVEL

If at least siteId and login are provided at command line level and there is not already a ./config/dragonfly2.properties file available, the values are taken and used to create an initial ./config/dragonfly2.properties, which then can be fine tuned via the configuration GUI in the JS web controlling app or by directly manipulating the file. The credentials are validated against the Accuware Dragonfly Cloud before they are written into the ./config/dragonfly2.properties file. In case of a failure, the start of the app is abandoned with an error.

Note: The command line parameters are no longer taken into account, if there is a valid ./config/dragonfly2.properties. Please note also, that the GUI is not automatically launched, if the initial configuration of the ./config/dragonfly2.properties has been performed by command line parameters. It is assumed, that intentionally no GUI is necessary, if one launches the app that way.

For example the launch request could look like so now:

java -jar -Djava.library.path="."                                      \
          -DsiteId="1000"                                              \
          -Dlogin="test@test.com"                                      \
          -Dpassword="testpassword"                                    \
          -DwebServerPort="4711"                                       \
          -DvpsServerUrl="https://myVPSServer.myDomain.com/api/v1"     \
          -DlogLevel="1"                                               \
      Dragonfly2Java.jar 

If the platform validation passes OK, a valid initial ./config/dragonfly2.properties is written and the app launches w/o bringing up the GUI.

CAM_SOURCE explained

The configuration parameter CAM_SOURCE is an important configuration parameter and has a couple of variances. The default value is -1, which advices the app to use the default system camera.

Other numerical values can be used and define the index of the camera as enumerated by the system. A list of available cameras can be obtained by the API function "Get list of cameras". There can be multiple indexes specified (comma separated, (e.g. left cam index","right cam index), so in case a stereo camera is made of two separate USB cameras.

On the other hand the parameter allows the specification of GStreamer pipelines or parameter strings to be used for by FFMPEG internally. The prefixes gstreamer: and ffmpeg: are used to decide, which internal API needs to be fed with the rest of the parameter string. Those pipelines can be used in order to mount external cameras via network or internet.

It goes without saying, that using GStreamer and/or FFMPEG requires to have the appropriate GStreamer 1.0 and FFMPEG APIs available on your system. This is the case if you have installed the Dragonfly app from the installation procedure provided here https://www.accuware.com/support/dragonfly-java-app-software-setup/.

Some ready to be used examples for pipeline configurations and FFMPEG parameters are given below. You might have to adapt the IP addresses and/or URLs:

GStreamer configuration to be used in order to consume a Raspberry Pi camera, streaming H.264 via TCP (Accuware Dragonfly Car)

The RPI is streaming RTP from 192.168.188.66, port 5000:

CAM_SOURCE=gstreamer:tcpclientsrc host=192.168.188.66 port=5000 ! gdpdepay !  rtph264depay ! avdec_h264 ! videoconvert ! appsink sync=false

Note: GStreamer target sink is always appsink.

GStreamer configuration to be used in order to consume a Raspberry Pi camera, streaming H.264 via RTSP

The RPI at 192.168.188.66 is providing an RTSP stream:

  CAM_SOURCE=gstreamer:rtspsrc location=rtsp://192.168.188.66:8554/test latency=0 buffer-mode=auto ! rtph264depay ! avdec_h264 ! videoconvert ! appsink sync=false

GStreamer configuration to be used to consume a web video, provided as RTSP stream

CAM_SOURCE=gstreamer:rtspsrc location=rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov latency=0 buffer-mode=auto ! rtph264depay ! avdec_h264 ! videoconvert ! appsink sync=false

FFMPEG configuration to consume a local MP4 video from disk

CAM_SOURCE=ffmpeg:/home/user/documents/test.mp4
CAM_SOURCE=ffmpeg:/home/user/documents/test.mp4 --startingFrame=500
CAM_SOURCE=ffmpeg:file://home/user/documents/test.mp4

FFMPEG configuration to consume an RTMP video from the web

CAM_SOURCE=ffmpeg:rtmp://184.72.239.149/vod/mp4:bigbuckbunny_1500.mp4

JConsole monitoring

If enabled, the function of the app can be monitored by using JConsole. If the Java app is running, run

jconsole

in a terminal window.

Enter username and password from ./config/jmx_password and hit Connect. On the next screen hit Insecure connection, because the JMX server doesn't support SSL. You will be able to monitor memory consumption, threads and CPU utilisation of the Java app.

CSV logging

If enabled, the app provides a CSV log of all positions made. This log can be found in the ./logs folder and is named positionlog.csv. It has an automatic daily rollover mechanism built in.

The log contains the following info elements, separated by ",". rxx parameters are the elements of the rotation matrix, state is the current positioning state at time of recording (see Get status)

EPOCH-timestamp-in-milliseconds,siteId,levelId,latitude,longitude,altitude,pitch,yaw,roll,r00,r01,r02,r10,r11,r12,r20,r21,r22,x,y,z,state

For example:

549567996549,1005,0,-0.000587,0.014597,-0.022552,-0.032113,-0.184232,0.677457,0.999925,-0.011822,-0.003222,0.011824,0.999930,0.000522,0.003215,-0.000560,0.999995,-8.44,1.21,0.84,NAVIGATION

Note: Not all elements must always be available for a given entry. Please also note the coordinate exchange at the metric coordinates x, y and z (explained in the paragraph Metric coordinates). Our "Z" is the commonly known "Y" and vice versa.

Local web server

By default the app exposes a local web server running at port WEBSERVER_PORT. You are on it if you can see this GUI.

REST API

There is no authentication/authorisation support on the REST API currently. However, SSL is supported.

All curl based examples are expecting a WEBSERVER_PORT that is equal to default 5000. The REST API is fully CORS enabled.

Summary

Currently 29 API functions plus 1 web socket interface are supported via REST. None of these functions have to be called mandatorily with the exception of Start positioning and Stop positioning, which are the only ways to start/stop mapping/positioning sessions after the Java app has passed the initialisation phase. Just a few of these API functions require Internet connectivity. Those are explicitly mentioned.

API function Purpose
Utilities
GET /api/v1/utils/status Get status
GET /api/v1/utils/errors Get errors
GET /api/v1/utils/config Get config
PUT /api/v1/utils/config Save config
GET /api/v1/utils/encrypt Encrypt string
GET /api/v1/utils/cameras Get list of cameras
PUT /api/v1/utils/restart Restart Java application
PUT /api/v1/utils/terminate Terminate Java application
GET /api/v1/utils/updateinfo Get software update info
Positioning
PUT /api/v1/positioning/start Start positioning
PUT /api/v1/positioning/stop Stop positioning
Mapping (general map information)
GET /api/v1/manage/maps/list Get list of maps
GET /api/v1/manage/maps/list/server Get list of maps from server
PUT /api/v1/manage/maps/reset Reset current map
Mapping (virtual markers)
GET /api/v1/manage/maps/markers Get list of virtual markers
GET /api/v1/manage/maps/markers/:id Get virtual marker
POST /api/v1/manage/maps/markers Create virtual marker
PUT /api/v1/manage/maps/markers/:id Edit virtual marker
DELETE /api/v1/manage/maps/markers/:id Delete virtual marker
Mapping (local operations on a specific map)
POST /api/v1/maps Save current map
GET /api/v1/maps/:map_name Load specific map
DELETE /api/v1/maps/:map_name Delete specific map
PUT /api/v1/maps/:map_name Update specific map
Mapping (map synchronisation with server)
GET /api/v1/manage/maps/list/deltas Get a summary of map deltas between client and server)
POST /api/v1/manage/maps/sync Sync with server
GET /api/v1/maps/sync Get general sync status
GET /api/v1/maps/sync/:id Get specific sync status
DELETE /api/v1/maps/sync/:id Cancel specific sync process
Mapping (visualization)
GET /api/v1/manage/maps/mappoints Get list of mappoints

Utility functions

Get Status

Obtain status. Result structure is also available as payload of the web socket status response.

Request-Resource: GET /api/v1/utils/status

curl localhost:5000/api/v1/utils/status -X GET

Response: 200 OK, 'application/json'

{
  "version": "1.3",
  "siteId": "1000",
  "deviceId": "D40K419JW256",
  "state": 1,
  "isStarted": false,
  "mapPointCount": 0,
  "markerCount": 0,
  "loopCount": 0,
  "fps": 0.0
}

Complete list of possible object properties. All of these are optional.

Response-Parameter Type Meaning
version String The version of the Java app and SDK plus the version of the native code plugin separated by '/'
deviceId String The unique device Id. Can be used in Accuware Dashboard for tracking
state Integer The positioning state. 0: Not ready, 1: Idle, 2: Map Initialization, 3: Navigation, 4: Lost, 5: Mapping
isStarted Boolean Whether or not positioning is running
mapPointCount Integer Mapping: Number of map points detected so far in this session
markerCount Integer Mapping: Number of markers detected so far in this session (printed and virtual)
loopCount Integer Mapping: Number of closed loops detected so far in this session
fps Double Camera: Number of frames per second achieved, current value
latitude Double Navigation: Currently known latitude of device (WGS-84)
longitude Double Navigation: Currently known longitude of device (WGS-84)
altitude Double Navigation: Currently known altitude of device (meters)
pitch Double Navigation: Rotation around the X-axis (degrees), see Pitch, yaw and roll explained
roll Double Navigation: Rotation around the Z-axis (degrees)
yaw Double Navigation: Rotation around the Y-axis (degrees)
x Double Navigation: Metric distance from the origin of the coordinate system along the X-axis in m see Metric coordinates
y Double Navigation: Metric distance from the origin of the coordinate system along the Y-axis in m
z Double Navigation: Metric distance from the origin of the coordinate system along the Z-axis in m
rotationMatrix Double[][] Rotation matrix, see below
levelId Integer Navigation: Currently known level Id of device
currentMapName String Mapping: Currently used map

Note: Depending on the current state, not all response parameter values must be contained in a given response.

Pitch, yaw and roll explained

Pitch, yaw and roll

The rotation matrix is provided as an array of arrays of doubles. More precisely

Double[][] rotationMatrix = new Double[3][3]

or

[
    [    r00,    r01,    r02 ],
    [    r10,    r11,    r12 ],
    [    r20,    r21,    r22 ]
]

Metric coordinates

In addition to the delivery of WGS84 coordinates (latitude, longitude and altitude) metric coordinates are delivered since v. 1.0. Those coordinates are always relative distances in m to the origin (0,0), if there is no other origin specified. This projection is known as ordinary 2D X/Y diagram. Since the Dragonfly axis names differ from the axis names in such a diagram, the following rules apply:

  • take x value as "X", positive values right, negative values left of (0,0)
  • forget about the y value. This value is always equal to the altitude value and cannot be displayed in a 2D diagram
  • mentally rename the z value to "Y", positive values above, negative values below (0,0)

Since the error of this projection can become relatively high and coordinates may become unusable, if the origin is not close enough to a bounding box of the delivered coordinates, there is a documented way to move the origin to another coordinate at Start positioning. The JS GUI makes use of this by providing the center coordinates and rotation of all available floorplans to the core. Now x, y and z are relative distances [m] to the center of a given, internally north-aligned floor plan (even if the real geographical rotation of a floor plan is a completely different one).

Get Errors

Retrieves a list of initialization errors. This API is just providing the errors happened while initializing the Java app part. It does not cover errors happening in the GUI part. API should not be used out of the context of the WebApp, since it doesn't give a complete picture.

Request-Resource: GET /api/v1/utils/status

curl localhost:5000/api/v1/utils/errors -X GET

Response: 200 OK, 'application/json'

{
}

Get config

Retrieve config as provided by ./config/dragonfly2.properties configuration file for the Java app.

Request-Resource: GET /api/v1/utils/config

curl localhost:5000/api/v1/utils/config

Response: 200 OK, ConfigurationObject, 'application/json'

{
  "site_id": "some_site_id",
  "site_username": "some_user_name",
  "site_password": "some_password_best_encrypted",
  "log_level": 7,
  "webserver_port": 5000,
  "webserver_ssl_supported": false,
  "webserver_keystore_file": "./config/keystore.jks",
  "webserver_keystore_password": "some_keystore_password_best_encrypted",
  "webserver_websockets_enabled": true,
  "jmx_remote_monitoring_enabled": true,
  "jmx_rmi_registry_port": 33985,
  "jmx_rmi_server_port": 33986,
  "audible_status_enabled": true,
  "cam_image_width": 640,
  "cam_image_height": 480,
  "cam_preview_option": 1,
  "cam_fov": 0,
  "cam_source": -1,
  "cam_mode": "mono",
  "cam_calibration_file": "mono.json",
  "map_calibration_method": 3,
  "position_upload_interval": 5000,
  "position_upload_store": false,
  "position_log_enabled": false,
  "video_recording_enabled": true
}

Note: Not all properties must be included in response payload. The content of the response is the same as documented here, all lowercased.

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Could not read config"
  ]
}

Save config

Request-Resource: PUT /api/v1/utils/config

curl localhost:5000/api/v1/utils/config -X PUT -d@config_file.json

Request-Parameter: ConfigurationObject, 'application/json'

Note: The payload of the request is a ConfigurationObject as shown in "Get Config". Except "site_id" and "site_username" none of the parameters is mandatory. Any change of configuration parameters requires a restart of the Java app,

Response: 200 OK, ConfigurationObject, 'application/json'

{
  "site_id": "some_site_id",
  "site_username": "some_user_name",
  "site_password": "some_password_best_encrypted",
  "log_level": 7,
  "webserver_port": 5000,
  "webserver_ssl_supported": false,
  "webserver_keystore_file": "./config/keystore.jks",
  "webserver_keystore_password": "some_keystore_password_best_encrypted",
  "webserver_websockets_enabled": true,
  "jmx_remote_monitoring_enabled": true,
  "jmx_rmi_registry_port": 33985,
  "jmx_rmi_server_port": 33986,
  "audible_status_enabled": true,
  "cam_image_width": 640,
  "cam_image_height": 480,
  "cam_preview_option": 1,
  "cam_fov": 0,
  "cam_source": -1,
  "cam_mode": "mono",
  "cam_calibration_file": "mono.json",
  "map_calibration_method": 3,
  "position_upload_interval": 5000,
  "position_upload_store": false,
  "position_log_enabled": false,
  "video_recording_enabled": true
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Configuration could not be saved"
  ]
}

Encrypt string

Function provides encrypted version of a string provided as value in query string. Result can be used everywhere in config, where encrypted values are accepted.

Request-Resource: GET /api/v1/utils/encrypt

curl localhost:5000/api/v1/utils/encrypt -G --data-urlencode "value=password"

Request-Parameter: Query-String

Parameter Meaning Default
value The string to be encoded n.a.

Response: 200 OK, 'text/html'

5D6D8A590CB4BA7E07F8FF84E7EF45E0

Get list of cameras

Function delivers a list of available cameras. The position of each listed camera can be used as parameter "CAM_SOURCE" in configuration, if a specific camera should be selected.

Note: The list of available cameras is not a static list. It changes with the addition/removal of cameras.

Request-Resource: GET /api/v1/utils/cameras

curl localhost:5000/api/v1/utils/cameras -X GET

Response: 200 OK, 'application/json'

[
  "HD Pro Webcam C920 0x14100000046d082d",
  "FaceTime HD Camera DJH4273WRR4F6VTDQ"
]

Restart Java application

Restart Java application. Does work only, if the Java app is launched as JAR (not from IDE)

Request-Resource: PUT /api/v1/utils/restart

curl localhost:5000/api/v1/utils/restart -X PUT

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Could not restart Java application"
  ]
}

Terminate Java application

Terminate Java application. Does work only, if the Java app is launched as JAR (not from IDE)

Request-Resource: PUT /api/v1/utils/terminate

curl localhost:5000/api/v1/utils/terminate -X PUT

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Could not terminate Java application"
  ]
}

Get software update info

Clients may obtain information about the availablitiy of a new software bundle version. Internally the Java app checks at startup and once per five minutes if there is a new software bundle version available server side. In case it is, the info is traced using the INFO tag to the console:

2019-02-18 13:35:03,841 SoftwareUpdateChecker$1$1 71 INFO  [I/O dispatcher 2]: Dragonfly2SDK:  New application version available: Version: x.xx, Linux download: https://s3.amazonaws.com/navizon.indoors.camera/dragonfly/dragonfly_update_linux_yyyymmdd.zip, macOS download: https://s3.amazonaws.com/navizon.indoors.camera/dragonfly_update_mac_yyyymmdd.zip

In parallel the GUI checks once per minute, if an update is available. In case it is, an alert is popping up once per session, which recommends you to update.

Request-Resource: GET /api/v1/utils/updateinfo

curl localhost:5000/api/v1/utils/updateinfo -X GET

Response: 200 OK, 'application/json'

{
  "version": "x.xx",
  "patch_url_linux": "https://s3.amazonaws.com/navizon.indoors.camera/dragonfly/dragonfly_update_linux_yyyymmdd.zip",
  "patch_url_macos": "https://s3.amazonaws.com/navizon.indoors.camera/dragonfly/dragonfly_update_mac_yyyymmdd.zip"
}

Response: 304 Not Modified

There is no new version available

Positioning

Function provides means to start and stop a positioning session. By using dontmap you advise the software to no longer accumulate mapping data, but navigate on the existing map.

Start positioning

Request-Resource: PUT /api/v1/positioning/start

curl localhost:5000/api/v1/positioning/start -X PUT
curl localhost:5000/api/v1/positioning/start&dontmap=true -X PUT

Request-Parameter: Query-String

Parameter Meaning Default
dontmap true: Disables simultaneous mapping, only navigating on an existing map false

Request-Parameter: Payload, 'application/json'

Parameter Meaning Default
array Optional array of objects, containing the Integer levelId and Double WGS84 coordinates of the origin for the metric projection (origin_lat, origin_lng, origin_alt plus the Double rotation of the floor plan in degrees) n.a.
[
  {
    "levelId": 1,
    "origin_lat": 25.xxxxxx,
    "origin_lng": -80.xxxxxx,
    "origin_alt": 0.0,                              // always 0, ignored
    "rotation": 170.0 
  },
  {
    ...
  }
]

The JS GUI is providing this array by specifying the center coordinates of all available floor plans of all possible levels.

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Could not open camera"
  ]
}

Stop positioning

Request-Resource: PUT /api/v1/positioning/stop

curl localhost:5000/api/v1/positioning/stop -X PUT

Result: 200 OK, 'application/json'

{
  "status": "success"
}

Mapping

Functions to list, load, save, edit, reset and delete maps locally plus functions to sync client and server maps.

Get list of maps

Request-Resource: GET /api/v1/manage/maps/list

curl localhost:5000/api/v1/manage/maps/list -X GET

Result: 200 OK, 'application/json'

[
  {
    "map_name": "map1",
    "description": "Room1",
    "checksum": "30b0f2e646e4373c2042de216d9a46be9778b775",
    "status": 1,
    "version": 1,
    "timestamp": 1515495422,
    "owner": "me@accuware.com",
    "access": 0
  },
  {
    "map_name": "map2",
    "description": "Room2",
    "checksum": "f7b6bd202b20d6822d4e36d27a9853ef381bdadf",
    "status": 1,
    "version": 5,
    "timestamp": 1515495422,
    "owner": "me@accuware.com",
    "access": 0
  }
]
Response-Parameter Type Meaning
map_name String The name of the map
description String The description of the map
checksum String 40 byte SHA-1 checksum over the map content
status Integer Status of the map, see below
version Integer Version number, up-counted on every change
timestamp Integer EPOCH timestamp in seconds of last change
owner String Accuware Username of the owner of the map
access Integer Access control flag (not used yet)
status Value Meaning
NOT_SYNCHRONIZED 0 Client map, not synchronised with server
SYNCHRONIZED 1 Client and server map identical

Get list of maps from server

An optional function to obtain a list of maps held by the server for informational purposes. This API function requires an Internet connection.

With the exception of the missing status property the payload returned is identical to the Get list of maps API.

Request-Resource: GET /api/v1/manage/maps/list/server

curl localhost:5000/api/v1/manage/maps/list/server -X GET

Result: 200 OK, 'application/json'

[
  {
    "map_name": "map3",
    "description": "Room3",
    "checksum": "30b0f2e646e4373c2042de216d9a46be9778b775",
    "version": 10,
    "timestamp": 1515495422,
    "owner": "you@accuware.com",
    "access": 0
  }
]

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "No Internet access."
  ]

Reset current map

Resets the currently used map. A running positioning session will be terminated.

Request-Resource: PUT /api/v1/manage/maps/reset

curl localhost:5000/api/v1/manage/maps/reset -X PUT

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Save current map

Put the current map results into a map named by map_name and give it a description. Both request payload parameters are mandatory and pre-processed. Only alphanumeric characters and some special selected characters are allowed (see regular expression below). The length of both parameters is limited. Both parameters are lower-cased, spaces are transformed to '_'

Request-Resource: POST /api/v1/maps

curl localhost:5000/api/v1/maps -X POST -H "Content-Type: application/json" -d '{"map_name": "map1", "description":"Map 1"}'

Request-Parameter: Payload, 'application/json'

Parameter Meaning Default
object Object containing mandatory map_name and description as strings. Allowed characters must match this regular expression: ^[0-9a-zA-Z\ _\-\.@]+$ n.a.

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "The system has not computed a map yet."
  ]
}

Load specific map

Request-Resource: GET /api/v1/maps/:map_name

curl "localhost:5000/api/v1/maps/map1" -X GET

Request-Parameter: URL-Parameter, urlencoded

Parameter Meaning Default
:map_name Mandatory name of the map to be loaded, urlencoded n.a.

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Map has been loaded and will be used for positioning.

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Map \"map1\" doesn\u0027t exist."
  ]
}

Delete specific map

Deletes the map named by parameter :map_name.

Request-Resource: DELETE /api/v1/maps/:map_name

curl localhost:5000/api/v1/maps/map1 -X DELETE

Request-Parameter: URL-String

Parameter Meaning Default
:map_name Mandatory name of the map to be deleted n.a.

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Map \"map1\" doesn\u0027t exist."
  ]
}

Update specific map

Request-Resource: PUT /api/v1/maps/:map_name

Allows to change map_name and/or description of the map named by parameter :map_name.

curl localhost:5000/api/v1/maps/map1 -X PUT -H "Content-Type: application/json" -d '{"map_name": "map1", "description": "New Description"}'

Request-Parameter: URL-Parameter, urlencoded

Parameter Meaning Default
map_name Mandatory name of the map to be deleted n.a.

Request-Parameter: Payload, 'application/json'

Parameter Meaning Default
object Object containing mandatory map_name and description as strings. Allowed characters must match this regular expression: ^[0-9a-zA-Z\ _\-\.@]+$ n.a.

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Map \"map1\" doesn\u0027t exist."
  ]
}

Map Synchronisation

The purpose of the Map Synchronisation process is to achieve equality of the maps held locally (on client) and remotely (on server). On client machines maps are located in the sub directory ./maps, grouped by Accuware Site Id. The folders contain zero or more map files (extension .osm) and a maplist.json file, which is used to hold meta data. It is not recommended to directly manipulate either of these files.

The structure below already shows, that the map name must be unique throughout an Accuware Site. The Java app is maintaining a File System Watcher, being triggered by either changes of map meta data (e.g. map_name or description). If Internet access is available at this moment, the Java app internally utilises the Get a summary of map deltas between client and server) API in order to determine the synchronisation state between client and server. It reports the results immediately via the web socket status API to the dashboard, which visualises the results. Version 1.3 just indicates, if a Sync with server request should be issued or not.

In addition the dashboard itself tries once per minute to determine the state to bring it to the user's attention.

.
├── 1000
│   ├── maplist.json
│   └── test.osm
└── 1005
    ├── maplist.json
    └── test.osm

2 directories, 4 files

For the function of the Dragonfly app it is completely sufficient to work with local maps only. Just in case you want to share maps with third parties or do a collaborative creation, utilisation or maintenance of maps a synchronisation process is necessary, which synchronises the maps available locally with the maps available server side for a particular Accuware Site.

The REST API Sync with server is intended to provide means to start such a synchronisation process.

There are some rules, enforced by the REST server while synchronising against the Accuware Servers:

Basic rules

  • Maps belong to an owner, which is formed by the currently used Accuware Site Username on creation
  • Only owners are allowed to create, rename and delete a map on the server
  • Anybody is allowed to update meta data of a map and - more importantly - to contribute to the map content (i.e. mapping)

Furthermore these Synchronisation rules apply:

Map available Synchronisation rule
On client only Maps owned by the user with the currently used Accuware Site Username: Will be created on server
Maps owned by somebody else: Will be deleted on client
On server only Maps owned by the user with the currently used Accuware Site Username: Will be deleted on server
Maps owned by somebody else: Will be created on client
On server and client Maps with a higher client version will be updated on server
Maps with a higher server version will be updated on client

TODO: Maps have unique names, so there cannot be two maps with the same name. However, with version 1.3 there is still a problem with maps, created from different owners, having the same name. The sync process would always let the map with the highest version number win, which in most cases will not show the desired results. This problem needs to be addressed in future versions.

Get a summary of map deltas between client and server

This API can be used in order to get a detailed overview about what is available

  • on client only
  • on server only
  • on client and server

The function internally determines the required actions and displays it. This API is just informational and used internally by the Java app. It is not necessary at all for the synchronisation request.

In order to proceed successfully an Internet connection is required.

Request-Resource: GET /api/v1/manage/maps/list/deltas

curl "localhost:5000/api/v1/maps/list/deltas" -X GET

Result: 200 OK, 'application/json'

{
  "status": "success",
  "clientOnly": {
    "createOnServer": [],
    "deleteOnClient": []
  },
  "serverOnly": {
    "createOnClient": [],
    "deleteOnServer": []
  },
  "clientAndServer": {
    "updateOnClient": [],
    "updateOnServer": []
  }
} 
Response-Parameter Type Meaning
status String Either "error" or "success"
clientOnly String Container object for maps existing on client only
serverOnly String Container object for maps existing on server only
clientAndServer String Container object for maps existing on client and server
createOnServer Array of String List of map names, which will be created on server on next sync
deleteOnClient Array of String List of map names, which will be deleted on client on next sync
createOnClient Array of String List of map names, which will be created on client on next sync
deleteOnServer Array of String List of map names, which will be deleted on server on next sync
updateOnClient Array of String List of map names, which will be updated on client on next sync
updateOnServer Array of String List of map names, which will be updated on server on next sync

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "No Internet access."
  ]

Sync with server

The synchronisation is always a client-initiated process using this API. Because it might need a lot of time (please note: big map files probably have to be up- and downloaded), this function just initiates a synchronisation process. In case, no other sync is currently running, it returns immediately, providing an ID, which furthermore can be used to obtain status and result or to cancel a sync process.

Request-Resource: POST /api/v1/manage/maps/sync

curl localhost:5000/api/v1/manage/maps/sync -X POST

Response: 200 OK, 'application/json'

{
  "id": 1
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Sync process with id 1 already running."
  ]
}

Get general sync status

This API call can be used in order to obtain the status of synchronisation process.

Request-Resource: GET /api/v1/maps/sync

curl "localhost:5000/api/v1/maps/sync" -X GET

Response: 200 OK, 'application/json'

{
  "status": "not running"
}

Get specific sync status

Obtains the status of a specific synchronisation process, identified by parameter :id, previously returned from a Sync with server API call.

Request-Resource: GET /api/v1/maps/sync/:id

curl "localhost:5000/api/v1/maps/sync/1" -X GET

Response: 200 OK, 'application/json'

{
  "status": "finished successfully"
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "No sync process with id 1 running."
  ]
}

Cancel specific sync process

Can be used in order to cancel a specific synchronisation process, identified by parameter :id, previously returned from a Sync with server API call. This call just abandons a synchronisation, it doesn't roll back the results, so the final state might be something "in between" and would probably need another sync request to return to a stable situation.

Request-Resource: DELETE /api/v1/maps/sync/:id

curl "localhost:5000/api/v1/maps/sync/1" -X DELETE

Response: 200 OK, 'application/json'

{
  "status": "cancelled"
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "No sync process with id 1 running."
  ]
}

Virtual marker management

Virtual marker operations do always work on the currently loaded and/or used map. A positioning session must be running and in order to make the most functions proceed, the positioning status must have been reached and kept.

Get list of virtual markers

Gets a list of IDs of virtual markers. The IDs can be used in subsequent API calls.

Request-Resource: GET /api/v1/manage/maps/markers

curl localhost:5000/api/v1/manage/maps/markers

Response: 200 OK, 'application/json'

[
  504,
  529
]

Get virtual marker

Get information for the virtual marker for ID :id

Request-Resource: GET /api/v1/manage/maps/markers/:id

curl localhost:5000/api/v1/manage/maps/markers/504

Response: 200 OK, 'application/json'

{
  "latitude": 2.5958528417757048E-5,
  "longitude": -3.495204476621969E-5,
  "altitude": 0.0,
  "levelId": -11
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "No reference point data for id 504"
  ]
}

Create virtual marker

Create virtual marker at position.

Request-Resource: POST /api/v1/manage/maps/markers

curl localhost:5000/api/v1/manage/maps/markers -X POST -H "Content-Type: application/json" -d '{"latitude": 0.0, "longitude": 0.0, "altitude": 0.0, "levelId": 0}'

Response: 200 OK, 'application/json'

Returns the ID of a newly created marker or -1

1492

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Could not add reference point. Positioning must be running and your device must not be in \u0027Lost\u0027 state."
  ]
}

Edit virtual marker

Edit virtual marker with ID :id

Request-Resource: PUT /api/v1/manage/maps/markers/:id

curl localhost:5000/api/v1/manage/maps/markers/1492 -X PUT -H "Content-Type: application/json" -d '{"latitude": 0.0, "longitude": 0.0, "altitude": 1.0, "levelId": 0}'

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "Could not edit reference point. Positioning must be running and your device must not be in \u0027Lost\u0027 state."
  ]
}

Delete virtual marker

Deletes virtual marker with ID :id

Request-Resource: DELETE /api/v1/manage/maps/markers/:id

curl localhost:5000/api/v1/manage/maps/markers/1492 -X DELETE

Response: 200 OK, 'application/json'

{
  "status": "success"
}

Visualization of mappoints

This API is only providing useful results under special conditions:

  • The configuration parameter MAP_CALIBRATION_METHOD must be set to 0
  • A mapping and positioning session must be running

The results are used internally to visualize the quality of mapping.

Get list of mappoints

Gets a list of map points.

Request-Resource: GET /api/v1/manage/maps/mappoints

curl localhost:5000/api/v1/manage/maps/mappoints

Response: 200 OK, 'application/json'

[
  0.4075704,
  0.14189786,
  0.52664083,
  -0.3725887,
  -0.18158877,
  0.26187122,
  -0.27079827,
  -0.24362804,
  0.6445207,
  0.1305532,
  0.39491752,
  ....
]

Response: 400 Bad Request, 'application/json'

{
  "status": "error",
  "errors": [
    "This API is available only if MAP_CALIBRATION_METHOD is configured to be 0"
  ]
}

Web socket to push general and map synchronisation status

As convenience method for obtaining general and map synchronisation status in real time the REST web server provides a web socket based status push service. The URL is ws://localhost:5000/websockets/status. The provided information matches generally the response payload of the Get Status and the Get a summary of map deltas between client and server REST API functions. However, due to the necessary discrimination between different payload types, an additional context identifier has been added (see samples below).

In case SSL is enabled on the web server, use wss://localhost:5000/websockets/status

Note: WEBSERVER_WEBSOCKETS_ENABLED must be true in ./config/dragonfly2.properties and the Java app must have started a positioning session. There is currently no web socket status update outside a positioning session (see Positioning), use ordinary Get Status in this case.

There are several ways to contact the web server for a web socket connection:

  1. The CURL approach:
curl --include \
     --no-buffer \
     --header "Connection: Upgrade" \
     --header "Upgrade: websocket" \
     --header "Host: localhost:5000" \
     --header "Origin: http://localhost:5000" \
     --header "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
     --header "Sec-WebSocket-Version: 13" \
     http://localhost:5000/websockets/status

Note: The console will show the raw web socket output

There are currently three different payloads carried via the web socket connection:

  • General status information
  • Map delta information
  • Image information (in case CAM_PREVIEW_OPTION contains the bit for the Javascipt display)

An example payload for a General status report looks like so:

Note: Depending on the current state, status may contain not all shown properties or even more. Please check

}?~?{
	"status": {
      "version": "1.3/2.1-b19",
      "siteId": "1000",
      "deviceId": "D40K419JW256",
      "state": 2,
      "isStarted": true,
      "mapPointCount": 0,
      "markerCount": 0,
      "loopCount": 0,
      "fps": 20.2429141998291
    }
}?~?{
	"status": {
      "version": "1.3/2.1-b19",
      "siteId": "1000",
      "deviceId": "D40K419JW256",
      "state": 2,
      "isStarted": true,
      "mapPointCount": 0,
      "markerCount": 0,
      "loopCount": 0,
      "fps": 20.2429141998291
    }
}?~?{
	"status": {
      "version": "1.3/2.1-b19",
      "siteId": "1000",
      "deviceId": "D40K419JW256",
      "state": 2,
      "isStarted": true,
      "mapPointCount": 0,
      "markerCount": 0,
      "loopCount": 0,
      "fps": 20.2429141998291
    }
    ...

An example Map Delta report (see Map Synchronisation) is indicated like so:

}?~({
  "deltas": {
    "status": "success",
    "clientOnly": {
      "createOnServer": [map1],
      "deleteOnClient": []
    },
    "serverOnly": {
      "createOnClient": [],
      "deleteOnServer": []
    },
    "clientAndServer": {
      "updateOnClient": [],
      "updateOnServer": []
    }
  }
}

For an description of the content see Get a summary of map deltas between client and server REST API.

An example payload for an Image report looks like so:

}?~({
  "image": {
    ....Base64 encoded JPG image payload...
  }
}

Since the payload is BASE64 JPG it can directly been stuffed into an HTML image tag (e.g. with ReactJS):

<img id="videoPreview" alt="Video Preview scaled down to 320x240" width="320" height="240" src={"data:image/jpg;base64," + this.state.image} />
  1. The Chrome approach:

There is a variety of Chrome plugins supporting web sockets. One of them is this. Install and enter the above mentioned status web socket URL into the address field.

More info?

Find usage information and more here Accuware

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.