Live Communications

Pegasus supports live communications via web-sockets.

Web sockets allow you to subscribe to a variety of events generated from pegasus. As a developer you can catch these events, and bring some life to your applications.

Pegasus Live communications ease programming by pushing the events to you, the developer, removing the need for periodic requests.

All live communications are handled by the server found in your site's api response under live_url.

You can go use that site to find a demo on how it's used, once loaded use the JS console to see the payload of the devices.

The supported socket-io.client library is v2.5.0

Note that polling is disabled on the server, you must use websocket as a transport to succesfully connect.

🚧

Note that we enforce an IP ban for clients that repeatedly get a 400; to avoid this use the websocket transport

Requirements

Pegasus' Live communications uses socket.io as its backbone. We highly recommend you take a look at their website to get a deeper understanding of how websockets work, as well as their implementation.
socket.io

In order to use the live functionality on your application. You need to download and run then socket.io client.
Get the socket client

While this documentation is focused on web applications, you can easily run socket.io from a nodejs or iojs server.

Emits

The live server emits some basic data, simply register some callbacks to the following handlers

socket.on('...', function(data){...})

HandlerDescription
_authenticatedAuthentication successful, sent when the live server has validaded your token with your gateway's API. Includes output of resources handler.
_errorGeneric error message. Authentication not successful, missing permissinos, etc.
_updateGeneric update message. ex. 'Listening to ...', or 'Stopped listenting to ...', etc.
resourcesReturns the resources you are allowed to register to. (vehicle ids, for vehicle events, triggers, etc.)
eventsPrimary events entry point. All events you have registered to will come in through here.

You can also emit some messages, with data to the live server as soon as you connect.

HandlerDescription
authenticateSend source and auth token to inititate authentication with live server.
resourcesRequest resources that are available to you.
listensubscribe to some or all entities for a given namespace
stopunsubscribe to some or all entities in a given namespace

Namespaces

All events generated by the Pegasus Gateway fall into namespaces.
By understanding the namespaces in use, you can further tune your application to only the events you need. This allows for more specialized programming.

Currently the gateway manages the following Namespaces:

NamespaceDescription
jobsJob related events (running, error, finished, etc)
triggersTrigger fired, trigger disabled, etc.
vehicle-eventsevents generated by the devices.
vehicle-nstat*deprecated on 1.9 changes in vehicle connectivity: ONLINE/OFFLINE state
* As of version 1.9 the vehicle-nstat was changed into the vehicle-events payload under device -> connection

Creating a socket


// Initialize the socket
// you must use websocket as the transport, polling (default) is disabled
var socket = io('https://aws-live-0.pegasusgateway.com/socket', {transports: ['websocket']})

Once you have the socket.io client loaded, lets make a fresh socket by initializing it.

Authenticating

// Set up basic handlers
socket.on('_authenticated', function(data){
    // this will fire when we are succesfully authenticated.
    // 'data' is equal to the output of /api/user/resources
    console.log(data)
})
socket.on('_error', function(message){
    console.error(message)
})
socket.on('_update', function(message){
    console.info(message)
})
socket.on('resources', function(resources){
    console.log(resources)
})
socket.on('events', function(envelope){
    console.log(envelope)
    namespace = envelope.namespace
    vehicle = envelope.object
    events = envelope.payload
})

var credentials = {
    pegasus: "https://cloud.pegasusgateway.com", // replace with your gateway.
    auth  : "aebf772e8aa25491ed273c699baf4d35aa5c4c0342cd7b51606bbf8c" // Retrieve the token by logging via /api/login
}

socket.emit("authenticate", credentials)

The first step in receiving events live from your Pegasus Gateway, is getting authenticated.

On successful authentication you'll be returned with the api/user response.

Now that you're authenticated you can subscribe to namespaces.

Listening

...

var envelope = {
    "namespace":"vehicle-events",
    "objects": 617, // [197,297] or "all"
}

socket.emit("listen", envelope)

In order to start listening to events, you must send an envelope via the listen message to the live server.

the evenlope must have the following properties.

  • namespace : Then namespace you are subscribing to (eg "vehicle-events")
  • objects : id or list of ids that you are subscribing to. You may also pass "all" to subscribe to all entities you have access to.

Check the console for any error or info messages reporting the status of the operation. Remember that these were handled via the _error and _update callbacks.

If everything checks out you will start receiving envelopes from the vehicle-events namespace via the events message.

socket.on('events', function(envelope){ ... })

The envelope will contain the following properties :

  • object : the object the events belong to.
  • payload : event or events
  • namespace: namespace the events belong to.

Compact events

You may have noticed that each payload received by the event handler contains a lot of duplicated data. This may be too much overhead for some applications. Some applications want to monitor only the changes on some fields, and act accordingly.

The webSockets interface supports compacted payloads which will significantly reduce the bandwidth of your application. It is important that you support these as soon as possible within your application as this will be enforced at a later date for all webSocket Subscriptions.

In order to enable compaction you first need to load some utilities into your application.

You can copy the snippet below.

// Utils and libraries
import _mergeWith from 'lodash.mergewith'
const ws_merger = (objValue, srcValue, key, object, source, stack) => {
  if (Array.isArray(objValue) && Array.isArray(srcValue)) return srcValue;
  return undefined;
};
const __cache = {}
// receive cached payload, update with compressed update, and return full event
const digest_ws_event = (update) => {
	const cached = __cache[update.primary_id] || {}
	__cache[update.primary_id] = _mergeWith(cached, update, ws_merger)
  const live_update = __cache[update.primary_id]
	let { updates, event, _event_restore } = update
	if (updates.includes('event')) {
		const { event: cevent } = live_update
		live_update.event = event
		_event_restore ??= []
		_event_restore.map((k) => {
			live_update.event[k] = cevent[k] || cached.device.latest.data?.[k]?.value
		})
	return live_update
	}
}
// event callback
const process_event = (update) => {
	const payload = digest_ws_event(update.payload)
	// application code
}

// cache callback
const cache_callback = (events) => events.map(process_event)

// attach function to events handler
socket.on('events', (event) => {
	process_event(event)
})

We are creating a util that will cache the initial full payload, and then our merge function will apply the compacted updates, and send the event down to your application.

You then need to enable the compact flag on the subscription

const envelope = {
  "namespace":"vehicle-events",
  "objects": 617, // [197,297] or "all" *
  "compact": true
}

socket.emit("listen", envelope, cache_callback)

** subscribing to 'all'

Using objects: 'all' with a cache_callback function in the subscription envelope could result in a high amount of data being serialized and sent.

You may receive some messages on the _error callback that represent the quotas being violated.

There is a limit of 250 entities per subscription that use the cache.

If you need to subscribe to multiple vehicles it is recommended you chunk/paginate your listen requests.

You can use the ids provided via the resources callback

import _chunk from 'lodash.chunk'

const $sleep = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms))

socket.on('resources', async function(resources){
  // resources.vehicles and resources.assets represent all ids that you can subscribe to
  for (const resource of ['vehicles', 'assets']) {
    for (const chunk of _chunk(resources[resource], 100)) {
      const envelope = {
        "namespace":"vehicle-events",
        "objects": chunk,
        "compact": true
      }
      socket.emit('listen', envelope, cache_callback)
      await $sleep(50) // recommended
    }
  }
})

Payload

The payload varies according to namespace.

vehicle-events

Received whenever a vehicle sends a tracking event.

The payload has a lot of keys, but the most important/relevant ones are:

device - contains information about the device, like connection/network status, trip info, state of the Inputs/Outputs
event - contains the values of the event keys reported
primary - info on the primary object/entity (vehicle, asset, etc)
secondary - info on the secondary object/entity (asset, bluetooth tag, etc)
updates - tells you what key updated (the event, or device, or both)

As mentioned above the primary and secondary keys correspond to the vehicle or asset that reported the value.
For example, when a driver (an asset) is identified via an iButton with the vehicle, the primary would be the vehicle, and secondary would be the asset.
When the secondary_id is null it means that the secondary info shows the last active info.
In other words, if the secondary_id shows a value it means the secondary is current, if there's no value in secondary_id the secondary is the last known.
So this would be useful for knowing if a vehicle currently has an asset assigned, if so, which one, and if not, which was the last asset assigned.

The payload keys and values are the same as the one's you will expect when consulting via Rawdata

Please note that the same payload may be received twice, what you have to keep track of is the updates key, because it will tell you if it's a device update such as a connection state change (from online to offline for example) or an event update, which means that a new event came in.
On your applications you'll want to show only when a new event came in, and handle the connection states when the device key is received.

Payload

Payload for vehicle-events

{
    "$$hashKey": "object:1229",
    "category": "vehicle",
    "device": {"ios_state": {…}, "gpsknit": {…}, "network": {…}, "lastrx": {…}, "trip_setup": {…}, …},
    "event": {"code": 12, "gpsknit_prev_lat": 3257884, "sv": 8, "dev_dist__mi": 3899, "event_time": 1504909832, …},
    "pid": 1,
    "primary": {"info": {…}, "associations": Array(3), "__updated": 1504110100.755031, "name": "Syrus 3 SIENNA", "trackers": Array(0), …},
    "primary_id": 686,
    "secondary_id": null,
    "type": "events",
    "updates": ["device"],
    "_pkey": "pka.05",
    "_site_url": "https://cloud.pegasusgateway.com",
    "_source": "pcore.listener",
    "_source_epoch": 1504910674.863004,
    "_ver_core": "1.9.0-rc1",
    "_ver_pcel": "2.1.1-r2"
}
KeyDescription
categoryevent category (vehicle)
deviceinformation on the device
eventevent information reported by device
pegasus_idunique ID for the pegasus site
pidunique ID to the pegasus site
primaryprimary entity
primary_idprimary entity id
pseqinternal use
route_statestate of the route
secondarysecondary entity
secondary_idsecondary entity id
site_idunique ID for the pegasus site
typetype of payload
updateskeys that are updated on this payload
_pkeyinternal use
_site_urlpegasus site URL
_sourceinternal use
_source_epochinternal use
_ver_coreinternal use
_ver_pcelinternal use
$$hashKeyinternal use

Detailed payload description

DEVICE

accel_state

Acceleration state

KeyDescription
ap_cur_deg_xcurrent degrees x plane
ap_cur_deg_ycurrent degrees y plane
ap_cur_deg_zcurrent degrees z plane
ap_cur_magcurrent magnitude (vector force in the direction it's moving)
ap_movtrue if moving
ap_ref_deg_xreference or configured x plane value at the time of calibration
ap_ref_deg_yreference or configured y plane value at the time of calibration
ap_ref_deg_zreference or configured z plane value at the time of calibration

asset

asset information
Key | Description
----|------------
aid | asset id
aid_source | source of the asset, ib for ibutton, btt for bluetooth tag, fp for fingerprint, rfid for RFID
btt_mac | bluetooth tag mac address
bttag | bluetooth tag associated info
bttag.asset_id | bluetooth tag asset id
bttag.created_at | bluetooth tag date of creation
bttag.edited_at | bluetooth tag date of edition
bttag.mac | bluetooth tag mac address
bttag.short_code | bluetooth tag short code
ib | ibutton HEX ID
last_aid_source | the last asset id source
rfi_full_id | rfid

config

configuration description

KeyDescription
devconfig_idunique id for the device's configuration
kyunique key for managed configurations
kydefconfiguration definition data (includes information about support for accessories and names of inputs/outputs)
kymissmatchonly present if the device is sending a ky different then the one configured on pegasus
kymodlast configuration modification time
pendingtrue if there's a configuration pending to be set
pending_countnumber of commands pending to be sent to the device from the new configuration
safeimmo_supporttrue if it's using managed configuration and it supports safe_immobilization on output 1
total_counttotal number of commands pending to be sent
valuesconfiguration values such as the speedlimit and rpm limit, among others.
_config_state1 if pending, 3 if synchronized
_epochtime of the last config modification

connection

connection state / information

KeyDescription
lastlast connection information
off_codescodes for reasons why it went offline
on_codescodes for reasons why it came back online
onlinetrue if device is online
_epochepoch timestamp of last connection change

dcounters

device counters

for a detailed description you can check the counters description

gpsknit

gps information

KeyDescription
ack_idinternal use
event_time__epochepoch timestamp of the event time
latlatitude
lonlongitude
no_gps_time_counttime in seconds with no gps coordinates
no_location_countnumber of consecutive events with no gps
no_location_fepochno location epoch timestamp
prev_ack_idinternal use
prev_event_time__epochprevious event epoch timestamp
prev_latprevious latitude
prev_lonprevious longitude
_epochepoch timestamp

imei

IMEI is the imei of the device

ios_state

state of the inputs and outputs

for a detailed description you can check the master field list

lastrx

last communication time

KeyDescription
msg_typetype of message
valuetimestamp it reported that message type
_epochtimestamp it was received

latest

latest data reported by the device

KeyDescription
counterslatest counters reported
datalatest data reported, same keys as rawdata more info
ioslatest ios reported
loclatest location information
prefixinternal use
vcounterslatest vehicle counters

lcounts

Listener counts, more information coming soon

legacy_set_out_state

current state of the outputs, useful for knowing if output is pending to be set/reset

KeyDescription
io_out[index]outputs 1-2 on device
io_exp_out[index]io expander output 1-4
cidcommand id
instructioncurrent instruction
set_atepoch time it was set at
uiduser id that set it

lrates

Listener rates, more information coming soon

muted_evs:

Muted or silenced events on the device information

net_reg

Network registration information

KeyDescription
cf_cidCell ID
cf_lacLocation Area Code
cf_mccMCC
cf_mncMNC
cf_rssiRSSI
cf_typeRegistration type (2g, 3g, lte, etc)
_epochNetwork information last update epoch

network

network information from device
Key | Description
----|-------------
cnum | carrier sim phone number (doesn't always reflect the number of the sim card due to restrictions from some carriers)
imsi | sim imsi
op | operator
sim | sim id
_epoch | epoch timestamp

outbox

Array with the commands pending to be sent to the device

KeyDescription
ctypeCommand type
idCommand ID
msgMessage to be sent to the device
timeTime message was placed on queue
uidUser ID that sent the message
usekyInternal use

photos

state of the cameras connected to the device

KeyDescription
camsobject with each camera's event id
evidevent id for photo captured
ncamsnumber of cameras connected to device
_epochtimestamp the data was reported

position_response

Information about the latest response to a position message while the device was offline.

satcom

Last satcom related information

safeimmo_state

current state of the safe immobilization

KeyDescription
cidcommand id
instructioncurrent instruction
set_atepoch time it was set at
uiduser id that set it
_epochtimestamp

set_out_state

Output activation information, whether or not an instruction is pending to be sent to manipulate an output

sigfox

Last sigfox related information

sim

SIM card related information including iccid, imsi, operator, and more.

trip

device trip information

KeyDescription
aidasset id associated to trip
dev_msgsinternal use
groupsid of the groups the vehicle belongs to during trip
idtrip id
kydevice configuration
methodtrip's method (gps)
movingtrue if vehicle is currently on a trip, false means parked
signalinternal use
src_idinternal use
src_typeinternal use
start_evdistancedistance traveled at the start of trip
start_latstart latitude
start_lonstart longitude
start_time_epochevent time at start of trip
system_time_epochsystem time at start of trip
vidvehicle id
_epochepoch timestamp

trip_session

device trip session information

KeyDescription
closing_datadata that closes the trip
first_eventopening event of trip
latest_eventlatest event
max_speedmax speed in mph
max_speed_hdopmax speed in hdop (value must be divided by 100)
max_speed_latmax speed location latitude
max_speed_lonmax speed location longitude
max_speed_timeepoch timestamp of max speed
opened_attime the trip session was opened
__persistentinternal use
__versioninternal use
_epochepoch timestamp of trip_session

trip_setup

KeyDescription
methodhow the trip is formed (whether with tracker or gps events)
stateraw trip message setup from Syrus, for more info check XATT on syrus manual
_epochepoch timestamp

vcounters

user editable vehicle counters, for more information go to counters

vehicle

vehicle information

version

KeyDescription
devicedevice model
extrasfirmware extra information
msgdevice message
numberversion firmware number

virtual_distance

virtual distance calculated via lat lon deltas

KeyDescription
evtime_epochtime the event was generated
latlatitude
lonlongitude
valuedistance for device
_epoch

virtual_ignition

virtual ignition calculated based on the status of the io_ign

KeyDescription
delta_distDelta total distance traveled
event_timeEvent time of last io_ign
idle_bufferIdle buffer
idle_counterIdle time in seconds
ign_counterIgnition time in seconds
io_idleIdle state
io_ignIgnition state
vidVehicle ID
_epochTime of last virtual_ignition change

event

list of event parameters reported by device, check out master field list for more info

vehicle-nstat *

Deprecated on 1.9 Received whenever a vehicle changes its ONLINE/OFFLINE status.

As of version 1.9 the vehicle-nstat was changed into the vehicle-events payload under device -> connection

Payload keys:

  • imei : (number) Device IMEI
  • vid : (number) Associated vehicle ID
  • online : (boolean) Connectivity status

You may receive other keys, they exist for testing, they may not exist on future releases.

Stopping

...

var envelope2 = {
    "namespace":"vehicle-events",
    "objects": "all", // [197,297] or 617
}

socket.emit("stop", envelope2)

In order to stop receiving events from some objects in a certain namespace, you simply send an envelope identical to the one used for subscribing via the stop message

FAQ

Device Network State

The device network state can be found under device.connection.online, true whenever the device is ONLINE.

Valid Position

There are 3 keys that can be used to find out whether the position of the event is valid, they're all essentially the same:
device.data.valid_gps also in the event's keys: event.valid_gps
device.data.valid_position also in the event's keys: event.valid_position
device.latest.loc.valid

Authentication Errors

Try updating the socket.io client to version 2.0.3 or higher.