WEB API

accessing party for end-users

Monitor - Set Up

Info: Stellantis Accessing Party for End-Users API for ex Groupe PSA brands (Citroën, DS, Peugeot, Opel and Vauxhall) is available only on request.

This tutorial explains how to set up monitors using the REST API. In order to do so, we will need to understand how to configure the notification and set up a triggering policy.

HTTP request headers used in this tutorial require to use realms.

Post Callback #

The first step is to configure a reusable configuration settings named callback. The same callback can be used for monitors and/or remote features of this API.

Registering a callback can be done using the following API. They are 3 types of callback notifications: WebHook, Push Notification, WebSocket.

1
2
3
4
5
6
7
8
9
10
$ curl \
  --request POST \
  --url 'https://api-cert.groupe-psa.com/connectedcar/v4/user/callbacks' \
  --data-urlencode 'client_id=<client_id>' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'x-introspect-realm: <realm>' \
  --key 'path/to/key.pem' \
  --cert 'path/to/client_cert.pem[:<cert_password>]' \
  --cacert 'path/to/ca_cert.pem' \
  --data '<check out HTTP body>' \
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "label": "<callback-name>",
  "type": ["Monitor", "Remote"],
  "callback": {
    "webhook": {
      "target": "https://my.post.callback",
      "name": "<webhook-name>",
      "batch": { "enabled": true, "size": 100 },
      "attributes": [ { "type": "Header", "key": "X-Vehicle_Id", "value": "$vin"} ]
    },
    "pushnotif": {
      "devices": ["<device_name>"],
      "attributes": [ { "type": "Header", "key": "X-Vehicle_Id", "value": "$vin"} ]
    },
    "websocket": {
      "target": "scheme://host[:port][/Path]",
      "batch": { "enabled": true, "size": 100 },
      "attributes": [ { "type": "Header", "key": "X-Vehicle_Id", "value": "$vin" } ]
    }
  }
}

Below is a description of the JSON body to configure the callback.

  • label is the name of the callback. 
  • type to declare a callback for Monitor, Remote or both.
  • callback allows to configure notifications, they can be of 3 different types:
    • webhook: for HTTP notification.
    • websocket: for websocket callbacks.
    • pushnotif: using Firebase Cloud Messaging in order to trigger push notification on iOS (APNs) or Android (GCM).
  • callback.<notification_type> allow to configure:
    • attributes: to setup additional attributes of the notification (headers, query params, body). These attributes are usually used for routing.
    • batch: webhook & websocket notifications can be send in batch, it’s recommended to use batch over single time notification.

If the callback is properly created the HTTP response body will look like:

1
2
3
4
5
{
  "_links": {  },
  "callbackId": "<id>",
  "status": "Running"
}

This message indicates that the callback has been sucessfully created with a unique identifier. This identifier, called {cbid} is required to create a monitor.

Post Monitor Request #

The following example is the structure of the HTTP request intended to set up the monitor according to the needs of a third party App.

The following path parameters are required, they need to be replaced by the appropriate value:

  • {id} is the id of the vehicle for which to register a monitor.
  • {cbid} is the id of a callback, this id is received when a callback is created.
1
2
3
4
5
6
7
8
9
10
$ curl \
  --request POST \
  --url 'https://api-cert.groupe-psa.com/connectedcar/v4/user/vehicles/{id}/callbacks/{cbid}/monitors' \
  --data-urlencode 'client_id=<client_id>' \
  --header 'Authorization: Bearer <access_token>' \
  --header 'x-introspect-realm: <realm>' \
  --key 'path/to/key.pem' \
  --cert 'path/to/client_cert.pem[:<cert_password>]' \
  --cacert 'path/to/ca_cert.pem' \
  --data '<check out HTTP body>' \
1
2
3
4
5
6
7
8
9
10
{
  "label": "<monitor-name>",
  "subscribeParam": { }, /* Monitor configuration Object */
  "attributes": {  }, 
  "extendedEventParam": ["vehicle.position", "vehicle.alerts"],
  "triggerParam": {     /* Triggering configuration Object */
    "triggers": [ ],    /* Triggers Events Blocs declaration */
    "boolExp": ""       /* Trigger Policy */
  }
}

Below is a description of the JSON body to configure the monitor, refer to API Reference for the specification of this endpoint.

  • label is the name of the monitor.
  • subscribeParam is the object for the configuration of the webhook:
    • refreshEvent: if the monitor is satisfied, refreshEvent define the period before its checked again. If the monitor is still satsfied after the refreshEvent period, a new notification will be sent.
  • attributes & subscribeParam.callbackAttributes: allows to add or to overwrite notification attributes (checkout callback creation). These attributes (vin, CallbackID, CallbackLabel, MonitorID & MonitorLabel) could be added to the path parameters, header or body of the notification, they are mostly useful for routing.

  • extendedEventParam array allows configuring the notification to include vehicle data in the notification. For example, if the monitor is intended to be triggered when the vehicle alarm is activated, it could be useful to add vehicle position in the callback.
  • triggerParam object allows configuring what triggers the callback:

Retry Policy: if the notification is not received by the server, the retry policy is enabled. Checkout the dedicated page for the description of this policy.

Post Monitor Response #

If the monitor request is properly set-up, the monitor will be created and an HTTP response will be returned:

1
2
3
4
{
  "monitorId": "c7eeaafdf0ab9683d5a1b8d51572014996540m0021",
  "status": "Created"
} 

This message indicates that the monitor has been successfully created with a unique identifier. This identifier is sent with every notification, therefore, it allows tracking this monitor.

Triggering Events Blocs #

As seen in the about page, monitors are triggered under the following patterns. Checkout the API Reference for the specification of trigger events.

  • 🗺️ Zone: a vehicle go in/out a circle area.
  • ⏱️ Time: a vehicle is being used within a time interval.
  • 🚗 Data: choose a sensor and set a triggering when the value is: equals to/greater than/lower than/include in/or changing.

The array triggerParam.trigger of the monitor creation request allows declaring and name the list of triggering event blocs.

Declaration of event blocs is not enough to describe the way the callback is being triggered, they must be used in the triggerParam.boolExp field in order to set up the triggering policy of this monitor.

Triggering Policy #

Once the triggers blocs are declared, they need to be combined together to create a triggering policy. To do so, we use a boolean expression syntax:

Grammar: Here is the list of available operands for monitors configuration.

  • AND: trigger1 & trigger2 if both conditions have to be triggered
  • OR: trigger1 | trigger2 if at least one condition has to be triggered
  • PARENTHESIS: trigger1 | (trigger2 & trigger3) to prioritize an expression over another
  • NOT: !trigger1 if the condition has to not be triggered

This is an example of boolean expression, where z1, z2, t1, t2, o1, o2, o3 are trigger bloc names:

1
2
3
4
5
6
7
8
9
10
11
{
  "label": "<monitor-name>",
  "subscribeParam": { },
  "triggerParam": {
    "triggers": [
      {"name": "z1" }, {"name": "z2" }, {"name": "t1" }, {"name": "t2" },
      {"name": "o1" }, {"name": "o2" }, {"name": "o3" }
    ],
    "boolExp": "((z1 & t1) | (z2 & !t1) | (o1 & z1) | (o2 & (z1 | t2))  | (o3 & (z1 | z2)))"
  }
}

In this boolean expression, the monitor will notify the server in all these situations:

  • (z1 & t1) = z1 AND t1 are being triggered
  • (z2 & !t1) = z2 is triggered AND t1 is NOT triggered
  • (o1 & z1) = o1 is triggered AND z1 is triggered
  • (o2 & (z1 | t2)) = o2 is triggered AND either z1 OR t2 is triggered
  • (o3 & (z1 | z2)) = o3 is triggered AND either z1 OR z2 is triggered

Examples: Autonomy #

This request asks to create a “Paris urban zone With Data Triggering:[vehicle.energy.electric.level] on Mondays” monitor with the following parameters:

  • The notification will include alerts and status of the corresponding vehicle.
  • This monitor is triggered if the vehicle’s electric autonomy is lower than 50% AND either is out of a 20 km radius circle of the center of Paris, France OR on Mondays.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{
  "label": "Paris urban zone With Data Triggering:[vehicle.energy.electric.level] on Mondays",
  "subscribeParam": {  }, 
  "extendedEventParam": [ "vehicle.alerts", "vehicle.status" ],
  "triggerParam": {
    "triggers": [
      {
        "name": "outOfParis",
        "zone": {
          "transition": "Out",
          "circle": {
            "radius": 20,
            "center": { "longitude": 2.333333, "latitude": 48.866667 }
          }
        }
      },
      {
        "name": "onMonday",
        "time": {
          "times": [
            {
              "recurrence": "Daily", "start": "PT14H30M",
              "occurence": {"day": ["Mon"]}, "duration": "PT04H30M"
            }
          ],
          "timeZone": "Europe/Paris"
        }
      },
      {
        "name": "batteryIsLow",
        "data": { "data": "vehicle.energy.electric.level", "op": "lowerThan", "value": ["50"] }
      }
    ],
    "boolExp": "((outOfParis & (batteryIsLow | onMonday)"
  }
}

Example: Heatwave #

Another example monitor to detect heatwave:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "label": "Paris urban zone With Data Triggering:[environment.air.temp]",
  "subscribeParam": {  }, 
  "extendedEventParam": ["environment.air.temp"],
  "triggerParam": {
    "triggers": [
      {
        "name": "outOfParis",
        "zone": {
          "transition": "Out",
          "circle": {
            "radius": 20,
            "center": { "longitude": 2.333333, "latitude": 48.866667 }
          }
        }
      },
      {
        "name": "outsideTemperatureIsHight",
        "data": { "data": "environment.air.temp", "op": "greaterThan", "value": ["30"] }
      }
    ],
    "boolExp": "(outOfParis & outsideTemperatureIsHight)"
  }
}

This request asks to create a heatwave monitor triggered inside the city of Paris, if the temperature is greater than 30 °C.

Example: Merged Monitors #

In place of having two different monitors like the previous examples, it’s possible to use a boolean expression in order to merge those 2 examples in only one monitor:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
  "label": "merged-monitor",
  "subscribeParam": { },
  "triggerParam": {
    "triggers": [
      { "name": "outOfParis" },
      { "name": "outsideTemperatureIsHight" },
      { "name": "onMonday" },
      { "name": "batteryIsLow" }
    ],
    "boolExp": "((outOfParis & (batteryIsLow | onMonday) | (outOfParis & outsideTemperatureIsHight))"
  }
}