This feature allows you to receive notification events when the following changes happen on avatars :
Notifications are not available for batch-like operations such as findAndDelete or findAndUpdate.
Notifications are configured thanks to triggers which describe what kind of changes you want to subscribe to and where the notifications should be sent.
Triggers have a maximum lifetime of 24 hours after which they are automatically deleted. Special notifications are sent to inform you about the current state of each trigger (ready, alive, expired or deleted).
Notifications are sent using two possible mechanisms :
In order to enable notifications, you have to use the triggers API, see the API documentation for detailed information about the available operations.
The main feature provided by the API are :
The Json payload to create a trigger :
{
"trigger_type":"ObjectPropertyTimeout",
"target":{
"domain":"http://www.example.com/",
"iri":"http://www.example.com/mysensor"
},
"object_property_target": {
"iri":"http://orange-labs.fr/fog/ont/transport.owl#isIn",
"timeout":20000
},
"webhook": {
"url":"https://my-wonderful-http-server/xx-42-yy"
},
"validity":3600000,
"user_data":"mycustomdata",
"response": {
"with_data":false
}
}
trigger_type
What kind of notifications are you looking for :
AvatarCreated
: To be notified of an avatar createAvatarUpdated
: To be notified of an avatar updateAvatarDeleted
: To be notified of an avatar deleteAnyEvent
: To be notified of an avatar change (create, update, delete)ObjectPropertyTimeout
: To be notified of avatar object properties timeouttarget
Describes the scope of the trigger.
domain
: Mandatoryiri
: Optional if you want to focus on a particular avatar IRI. ''This iri must of course belongs to the specified domain''.object_property_target
Only used when trigger_type
is ObjectPropertyTimeout
iri
: Object properties iri to be notified if an avatar spent too much time on it. Only http://orange-labs.fr/fog/ont/transport.owl#isIn
is supported.timeout
: Delay in milliseconds > 10s & < 24hwebhook
If you provide this field, then your trigger is a webhook based trigger if you don't provide it then automatically we assume you want a "websocket" one and in that case you'll receive the dynamically provisionned websocket URL in the create response.
url
: The URL of your listening webhookvalidity
user_data
response
with_data
: true if you want to receive all data associated to the avatars. (data properties & object properties)A received response example when creating a websocket trigger :
{
"uuid": "3908441c-fa9a-4d4e-a8dd-6676a73bdc66",
"trigger_type": "AnyEvent",
"validity": 3600000,
"target": {
"domain": "http://www.example.com/"
},
"response": {
"with_data": false
},
"websocket": {
"url": "ws://notifier.thinginthefuture.com/connect/3908441c-fa9a-4d4e-a8dd-6676a73bdc66",
"uuid": "3908441c-fa9a-4d4e-a8dd-6676a73bdc66"
},
"user_data": "mycustomdata",
"created_on": 1625218061067,
"expires_on": 1625221661067,
"owner": "3c78d7c4-d1f4-4666-bbdf-3118fea0b744"
}
As you can see here, no webhook was provided on create, so we assumed it is a websocket trigger and that's why you receive within the response the websocket.url
and websocket.uuid
fields.
The provided webhook or the connected websocket clients will receive the same messages encoded as JSON objects. There is two kind of messages :
Sent trigger status notification messages are using this format :
{
"state": "deleted",
"uuid": "8bddaa56-6a53-4fbc-bb62-f996c8044915",
"epoch": 1612357976709,
"user_data": "42"
}
state
the value means for either the websocket or the webhook :
ready
: Trigger created, everything is readyalive
: Every 30s it tells you everything is still finedeleted
or expired
: The trigger has been removed or has expired, for websockets all established connections are then closed.uuid
A reference to the trigger UUID (Websocket and trigger UUID are kept in sync, keep in mind to use the UUID provided in the websocket.uuid
field even if the value is the same as for the trigger UUID).
epoch
epoch time in milliseconds from where the message has been sent.
user_data
Only available for webhook, it brings you back with the data you have provided when the trigger has been created.
Sent avatars notifications messages are using this format :
{
"notification_id": "494dac1a-45ce-4cb8-9aa0-6bc8f9520b75",
"trigger_uuid": "b49ad8ef-4850-41f2-aade-6f709b0f2684",
"event": {
"timestamp": 1612171747088,
"event_type": "OBJECT_PROPERTY_TIMEOUT",
"context": [
{
"avatar_uuid": "ad49ef5d-7ed4-402b-b760-beffbc23b9dc",
"avatar_iri": "http://www.example.com/blah/tag-indoor-123821345678",
"avatar_domain": "http://www.example.com/blah/",
"object_property_iri": "http://orange-labs.fr/fog/ont/transport.owl#isIn",
"from_avatar_iri": "http://www.example.com/blah/tag-indoor-4567821345678",
"to_avatar_iri": "http://www.example.com/blah/tag-indoor-123821345678"
}
]
},
"kind": "NotificationCapsule",
"request_id": "16",
"data": []
}
or
{
"notification_id": "f11880b0-c5b5-4980-a269-b6c4eaf4fd8c",
"trigger_uuid": "fbc7ed6b-c3a8-4def-a2e5-6d40be245057",
"event": {
"timestamp": 1611674131705,
"event_type": "AVATAR_CREATED",
"context": [
{
"avatar_uuid": "564fac5d-2197-4cf5-905f-56578b9be210",
"avatar_iri": "http://www.example.com/barn-outside-lamp-2",
"avatar_domain": "http://www.example.com/"
},
{
"avatar_uuid": "9c9f263b-ca21-494f-9e07-ad41926693ab",
"avatar_iri": "http://www.example.com/barn-outside-lamp-1",
"avatar_domain": "http://www.example.com/"
},
...
{
"avatar_uuid": "44407574-ee1c-49c6-a5ea-4002a985166c",
"avatar_iri": "http://www.example.com/home-meteo-device",
"avatar_domain": "http://www.example.com/"
}
]
},
"kind": "NotificationCapsule",
"request_id": "1",
"data": [
{
"_uuid": "564fac5d-2197-4cf5-905f-56578b9be210",
"_iri": "http://www.example.com/barn-outside-lamp-2",
"_domain": "http://www.example.com/",
"_classes": [
"http://elite.polito.it/ontologies/dogont.owl#Lamp"
],
"_static": false,
"_visibility": 0,
"_last_updated": 1611674128125,
"_depth": 0,
"_owner": "admin",
"http://elite.polito.it/ontologies/eupont.owl#description": "Exterior Lamp for the large car door\"@e",
"http://www.opengis.net/gml/pos": "{\"type\": \"Point\", \"coordinates\": [-2.050771, 48.316220]}",
"_outE": [
{
"_property": "http://elite.polito.it/ontologies/dogont.owl#isIn",
"_iri": "http://www.example.com/barn",
"_uuid": "456e31e9-5727-479a-8fef-726ae26fbb37"
}
]
},
...
Notes :
with_data
option has been set to true.Prerequisites :
curl
and jq
commands are availableexport THINGIN_TOKEN="Bearer $(curl -su $THINGIN_USERNAME:$THINGIN_PASSWORD $THINGIN_API/auth)"
with : THINGIN_API=https://coreapi.thinginthefuture.com
POST /recorder Create a JSON recorder
operationcurl -X POST "https://mapland.fr/echo/api/recorder"
to get it{"uuid":"xxx-yyy","url":"https://mapland.fr/echo/api/echoed/xxx-yyy"}
url
field is your new freshly created json recorder which can be used directly as a webhook endpoint.TRIGGER_JSON='{
"trigger_type":"AnyEvent",
"target":{
"domain":"http://www.example.com/"
},
"webhook": {
"url":"https://mapland.fr/echo/api/echoed/xxx-yyy"
},
"validity":3600000,
"user_data":"mycustomdata",
"response": {
"with_data":false
}
}'
curl -vL \
-H "Content-Type: application/json" \
-H "Authorization: $THINGIN_TOKEN" \
-d "$TRIGGER_JSON" \
https://coreapi.thinginthefuture.com/triggers
For example add a new avatar on the monitored domain example.
Just visit your webhook end point to visualize what has
been sent by thing'In.
curl -s https://mapland.fr/echo/api/echoed/xxx-yyy | jq
The prerequisites are the same as for the previous example
TRIGGER_JSON='{
"trigger_type":"AnyEvent",
"target":{
"domain":"http://www.example.com/"
},
"validity":3600000,
"user_data":"mycustomdata",
"response": {
"with_data":false
}
}'
RESPONSE=$(
curl -vL \
-H "Content-Type: application/json" \
-H "Authorization: $THINGIN_TOKEN" \
-d "$TRIGGER_JSON" \
https://coreapi.thinginthefuture.com/triggers
)
echo $RESPONSE | jq
Note : We have a small limitation here as we may respond before the websocket is fully allocated, you may have to wait a little bit (1 or 2 seconds) before trying to connect any client to the allocated websockets.
Extract the allocated websockets end point from the previous response :
WEBSOCKET=$(echo $RESPONSE | jq -r .websocket.url)
Create a JSON recorder and ask him to connect to the allocated websocket:
RECORDER=$(curl -sX POST "https://mapland.fr/echo/api/recorder")
RECORDER_URL=$(echo $RECORDER| jq -r .url)
RECORDER_UUID=$(echo $RECORDER| jq -r .uuid)
curl -s -X POST "https://mapland.fr/echo/api/echoed/${RECORDER_UUID}/websocket" \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-d "{\"uri\":\"${WEBSOCKET}\",\"userData\":\"42\"}" | jq
curl -s ${RECORDER_URL} | jq
Just change the payload to :
{
"trigger_type":"ObjectPropertyTimeout",
"target":{
"domain":"http://www.example.com/"
},
"object_property_target": {
"iri":"http://orange-labs.fr/fog/ont/transport.owl#isIn",
"timeout":20000
},
"webhook": {
"url":"https://mapland.fr/echo/api/echoed/xxx-yyy"
},
"validity":3600000,
"user_data":"mycustomdata",
"response": {
"with_data":true
}
}
Create this trigger, then create an Avatar with an isIn
object properties and wait ~20s to be notified on the provided webhook.