DEV Community

Tech Community for Software AG Tech Community

Posted on • Originally published at tech.forums.softwareag.com on

Step-by-step instruction for Cumulocity Notification 2.0

Introduction

Cumulocity Notification 2.0 is the latest version of the notification API. It is an improved version of Cumulocity real-time notification API with stronger delivery semantics and ordering guarantees. To be able to receive the real-time notifications, a consumer application or microservice needs to first create a subscription and obtain a token from the messaging service hosted by Cumulocity IoT.

In this article, you will learn some relevant definitions and how to use the Cumulocity Notification 2.0 API.

Pre-requisite

Before you start, please confirm:

  • your user account has ADMIN permission for the permission type “Notification 2”
  • Cumulocity Messaging Service needs to be enabled (only need to check when the cloud instance older than 10.13, dedicated and self-hosted instances older than 10.11)
  • Shared token only supported from 10.16

Glossary

Subscription

The subscription defines the scope and type of notifications the consumers will receive. It is created by sending a request to the Notification 2.0 subscription API /notification2/subscriptions with the JSON format definition in the request body.

A subscription is identified by a subscription name, which must be declared in the request body. The request body also requires the value of ‘context’ to be specified. This determines whether the subscription is for a single device or for the entire tenant. If the value of the context is ‘tenant’, which means the subscription is for the whole tenant, then the device ID is not required. If the value of the context is mo, which represents managedObject, then the device ID must be given in the source. Optionally, you can filter the notifications for specific APIs or types using subscriptionFilter. For more information please check the OpenAPI Specification of Cumulocity.

Consumer

Consumer can be an application or microservice that you build. With a valid token, the consumer will receive messages that match the scope specified in the subscription. When you establish the WebSocket connection, you can name consumers in the request header of consumer protocol as an optional parameter to distinguish them. E.g. notification2/consumer?token=xyz&consumer=instance1. If a consumer uses the shared token, it is a shared consumer.

Subscriber

When a token is created using the Token API, a Subscriber is created at the same time. When unsubscribing a subscriber, the appropriate token is required in the request parameters. It’s identified by its unique name. If the token is the type of shared, one token of a subscriber can be used by multiple shared consumer.

Token

The token is used to authorize the consumer to ensure that the holder is allowed to connect and receive the subscription notifications. It has a dedicated Rest API to create the token:

/notification2/token.

The subscriber name and subscription name must be specified in the body of the request. The subscription name should be the same as the name used to create the subscription.

You can also set the expiration time and type of token in the request, as well as whether the token is signed and whether it is persistent.

Starting from Cumulocity IoT 10.16, C8Y Notification 2.0 supports the creation of shared tokens. Shared tokens allow one important pattern: The parallelization of the consumer client workload for a notification subscription. When a shared token used by multiple consumers, every notification will be sent to one of the consumers based on a implemented shared algorithm according to the ID of the source. All notifications for a given ID will be delivered to the same consumer. This can be helpful when the consumer can’t process notifications faster than they arrive for multiple IDs.

Connectivity

A secure WebSocket connection is used to consume notifications by a consumer / client. The C8Y tenant domain is the endpoint for the WebSocket connection, but the URI schema https:// or http:// should be replaced by wss:// or ws://. The URL path for creating connection is /notification2/consumer/ . There is one required argument, the token collected from the platform. You can also add the customer’s name here as an argument. To keep the WebSocket connection alive for a long time, you should let the client send a ping message to the server regularly. In case of connection interruption the client should implement a reconnect function.

Get started with Notification 2.0

Here I will show you the basic steps to create the Notification 2.0 connection using a Python script. Of course, you can follow these steps with any other programming language. First, let’s see how to collect notifications using an exclusive consumer.

Create a subscription

The first step is to create a subscription using subscription API of Notification 2.0:

POST /notification2/subscriptions

Enter fullscreen mode Exit fullscreen mode

In the request payload, you need to define the scope of notifications that you would like to receive. It is achieved by the context and subscription filter in the payload. You can subscribe to a specific device using context = mo, or create a subscription across the entire tenant scope with context = tenant. When the context is mo, the device ID is required in the request body. And the subscription filter is available for “alarms”, “alarmsWithChildren”, “events”, “eventsWithChildren”, “managedobjects”, “measurements” and “operations” when context is mo, while tenant context supports “alarms”, “events” and “inventory” subscription filter.

You can appoint the type of data to subscribe to. typeFilter further narrows the scope of a subscription. You can specify one type or use operator or to specify multiple types.

Here is an example of subscription payload with tenant context and filters:

subscription_json = {
    "context": "tenant",
    "subscription": "SubscriptionA",
    "subscriptionFilter": {
        "apis": [
            "alarms",
            "events",
        ]
        "typeFilter": "'c8y_BootEvent' or 'c8y_UnavailabilityAlarm'"
    }

Enter fullscreen mode Exit fullscreen mode

Here is an example subscription payload for mo context:

subscription_json = {
    'context': 'mo',
    'subscription': 'SubscriptionB',
    'subscriptionFilter': {
        'apis': [
            'measurements'
        ],
        'typeFilter': 'c8y_Measurement'
    },
    'source': {
        "id": "12345"
    }

Enter fullscreen mode Exit fullscreen mode

When you create the subscription successfully, you will get a response with the id of the subscription. It’s useful for the following steps.

Create a token

To be able to receive the notifications, a token should be first obtained from the token API of Notification 2.0:

POST /notification2/token

Enter fullscreen mode Exit fullscreen mode

The payload of this request requires subscription name and subscriber name. The subscription name must match the name of the subscription created earlier.

Here is an example of token request payload:

token_json = {
    'subscription': 'SubscriptionA',
    'subscriber': 'Subscriber1'
}

Enter fullscreen mode Exit fullscreen mode

If you create the token successfully, you will receive a response containing a token string.

Establish the connection

Now you should have all you need to establish the WebSocket connection. First don’t forget to check the URI schema to ws:// or wss://. I used Python library websocket-client to create a long-lived connection.

ws_client = websocket.WebSocketApp(
    C8Y_BASEURL_WEBSOCKET + '/notification2/consumer/?token=' + token_response['token'],
    on_open = open_handler,
    on_message = message_handler,
    on_error = error_handler,
    on_close = close_handler
)
ws_client.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}, ping_interval=30)

Enter fullscreen mode Exit fullscreen mode

As you can see in the example above, a WebSocket client has been created using the consumer API of Notification 2.0 with the token. If there are new data generated by REST or MQTT APIs and they meet the subscription scope, the web socket client will get the notifications. The message_handler function will send acknowledgement and get notifications.

Stop the connection

If you only close the WebSocket connection, the subscription will still exist. Then the notifications come after the disconnection will buffered on the platform. So to prevent unnecessary usage of the platform resources, don’t forget to delete the subscription and unsubscribe the subscriber when you stop the connection.

First, delete the subscription. It will stop the buffering of the new notifications. The ID here is the subscription ID you reserved when you created the subscription.

DELETE /notification2/subscriptions/{id}

Enter fullscreen mode Exit fullscreen mode

Then, unsubscribe the subscriber. It will delete the buffered notifications. Note, that the token does not have to match the token you’ve used to initially connect. You can just create a new token with the same payload for that purpose if desired.

POST /notification2/unsubscribe/?token={{the-token}}

Enter fullscreen mode Exit fullscreen mode

Notification 2.0 with shared token

Here you will need two Python scripts to subscribe to Notification 2.0 to simulate two consumers. The shared token for now only supports the mo context.

Notifications are delivered to all consumers based on the device ID. Notifications with the same device ID are sent to the same consumer. This means that the more devices there are, the more evenly the notifications will be distributed.

Then you might ask if you need to create separate subscriptions and tokens for each device. The answer is yes, you need to send separate requests to create subscriptions for each device but with the same subscription name and same subscription settings (context and subscription filter). Then you only need to create one subscriber for all the subscriptions and obtain the token. When this token is shareable, multiple consumers will receive the notifications from different devices.

Create the subscriptions and the first consumer

In this case, you need to prepare some more devices and create subscription for each device with the same subscription name.

Compared to creating a exclusive consumer, creating the first consumer with a shared token requires an additional declaration of the shareable property of the token. For this you need to add a key-value pair 'shared': True in the request payload for creating the token. You can follow the instruction above and add the following parts.

token_json = {
   'subscription': 'SubscriptionA',
   'subscriber': 'Subscriber1',
   'shared': True
}

Enter fullscreen mode Exit fullscreen mode

In order to identify the consumer and keep the notifications with their consumers when the connection is broken, it is recommended to define the consumer name when you connect the WebSocket.

wss: {{cumulocity-domainname}}/notification2/consumer/?token={{shared-token}}&consumer={{uniqueconsumername}}

Enter fullscreen mode Exit fullscreen mode

You need to keep the shared token for other consumers.

Create the second consumer

As the subscriptions and token have been created during the creation of the first consumer, this consumer (or more other consumers) only need to establish the WebSocket connection with its name and the same shared token. As the first consumer covers the subscription deleting and subscriber unsubscribing, it’s not required to perform them here.

Test the consumers

Now, when you create some data that covered by the subscriptions using REST or MQTT APIs, both of the consumers will receive notifications from different devices.

Summary

Now you should know how to use the Notification 2.0 API. You can check the full scripts for subscribing to Notifications 2.0 with and without a shared token here:

https://cumulocity.com/api/core/10.16.0/#tag/Notification-2.0-API

Useful links | Relevant resources

Introducing the new Cumulocity Notifications 2.0 API
https://cumulocity.com/api/core/10.16.0/#tag/Notification-2.0-API

Read full topic

Top comments (0)