Application Providers

Version 1.9.8

Last updated: 2018-09-05

Overview

Follow these steps to configure your application to query device data from the Geeny platform.

Demo: Lighty

Geeny demo apps

In the Geeny demo flow, Lighty is a fictitious Application Provider with an app for controlling a smart light bulb. Lighty has completed the onboarding process, and now the developers of Lighty can configure the app to access data from other smart devices — for example, a Kadabra smart lock.

Under the hood, Lighty is a working example of an onboarded Application Provider. Click here to view the source code on GitHub.

Step 1: Set up application on the Geeny platform

You must register your application on the Developers Dashboard and then tell the Geeny platform which data sources (Thing Types) and data types (Message Types) it can interact with.

  1. Log in to developers.geeny.io.
  2. At the bottom of the screen, click the button labeled Register your Application. Register your application
  3. Enter a name for your application and click Create Application.

Your application has now been added to Geeny. You can find it listed on the Developers Dashboard under Applications.

Click the Settings tab at the top of the screen. On this screen, you will find a unique ID for your application. You’ll need this ID to authenticate your application with Geeny, so write it down somewhere.

Application ID

Add Thing Types & Message Types

Now that your application is registered, you need to specify the data sources (Thing Types) whose data your application will access (in the form of Message Types).

  1. From the Developers Dashboard, click on your application and then select the Data Sources tab.
  2. Scroll down to the bottom and click the Add Thing Types button.
  3. A list of available Thing Types will appear. Click the + icon next to the Thing Type you want to add to your application.

You will then be taken back to your application. Notice that your application now shows a Thing Type in the Thing Types section and each of the Thing Type’s Message Types in the Message Types section.

If you want to add more Message Types to your application, click the Add Message Types button and follow the same process as above.

Removing Thing Types and Message Types

Each Message Type has a button to the right (labeled with a -) that allows you to remove it from your application. To remove a Thing Type, you must remove all of its Message Types first.

Important: Your application access key

Geeny will produce an API access key for your application when you register it. You must supply this key with your application’s API calls. You can find generate this key on the application’s Settings tab:

Application access key

Click the Generate button to generate the key. Once you generate the key, it will be available on this page indefinitely. You can revoke it and issue a new one from this page as well.

Step 2: Implement Geeny Connect flow to Thing Provider

Now that you have completed the Geeny side of the setup process, you must implement a login flow to trigger when a consumer wants to connect a device from a Thing Provider to your application.

Requesting and configuring OAuth access

To enable the OAuth flow for your application, you must request access to it. Go to your application’s details page and then click the OAuth tab. Then, click the button labeled Request OAuth access.

Request OAuth access

Geeny will approve your application and generate OAuth configurations for your application, which will be displayed on the OAuth tab. Geeny will then provide you with the necessary configuration to use the Geeny OAuth feature in your application.

Configure OAuth access

Finally, add your preferred OAuth Redirect URI. This is the URI where consumers will be redirected after authorizing your application.

Getting the access token

Get authorization code

To register a user (e.g., using a “Log in with Geeny” button), redirect them to /oauth2-provider/authorize and pass the following to the query string:

  • redirect_uri: One of the redirect URIs you specified when you registered your application.
  • client_id: Your application’s client ID.
  • response_type: Set this to code to use the authorization_code grant.
  • scopes: For granting additional permissions besides reading the user’s profile (read-profile).
    • NOTE: read-profile is currently the only implemented scope.

Sample URL to trigger the authorization:

GET https://connect.geeny.io/oauth2-provider/authorize/?redirect_uri=http://docs.geeny.io&client_id=939e5db1-83hr-c193-bb4d-718a2cf5e862:11&response_type=code&scopes=read-profile

Geeny Connect will then display the OAuth 2 Authorization screen to the user and request a set of specific permissions for accessing their device.

Get the token

When the user authorizes your application, the Geeny platform will redirect them to the provided redirect_uri and append the authorization code to the URI. Example:

https://docs.geeny.io/?code=mSJS8ictPVl85gNDIf3mAL93h8g3c

Use this code in a request to /oauth2-provider/token, which will return the actual token.

URL:

POST https://connect.geeny.io/oauth2-provider/token/

Headers:

Authorization: <your-application-token>

Parameters:

Name Type Required? Description
applicationId string(UUID) Yes ID of the application sending the command.
messageTypeId string(UUID) Yes ID of the Message Type used for sending the command.
messageId string(UUID) No Optional UUID to assign to this message.
messages array[Object] Yes Array of commands to be delivered to Things. Includes the payload (base64-encoded payload of the command), userId (user ID of the Thing owner), and thingId (ID of the Thing to receive this command).

Sample call using cURL:

curl -X POST "https://connect.geeny.io/oauth2-provider/token/" -F "redirect_uri={your-application-redirect-uri}" -F "code={from-the-previous-call}" -F "client_id={your-client-id}"  -F "client_secret={your-client-secret}" -F "grant_type=authorization_code"

Sample response:

{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9...",
    "expires_in": 86400,
    "token_type": "JWT",
    "state": null,
    "scopes": "read-profile read-subscriptions"
}

The access_token property contains your access token in the form of a JWT.

Getting Geeny user ID from the token

When a consumer authenticates with your application in the process detailed above, Geeny will create a Geeny user ID for them under the hood. This identifier is mapped to the one generated on your end and the one generated by the Thing Provider. All messages transmitted to the Geeny platform by this consumer’s Things will be keyed with this Geeny user ID.

The Application Broker API enables applications to query device data. By default, when you request data of a specific Message Type (as explained below), it will return a list of messages sent by all users who have authorized your application to access their data along that specific Message Type. You will need parse the response for the correct messages to show the user in your application using this Geeny user ID.

To get this ID, you must decode the access token from the previous step. The ID is stored in the user_id property.

Refreshing the token

If you try to use an expired token against a Geeny API, you will get a 401 Unauthorized error with the response content: {"detail": "Signature has expired"}.

When you need to refresh the token, pass it to the /oauth2-provider/token endpoint and you will get a new token back.

If the refresh period (15 days) has expired, you will get a 401 Unauthorized error.

Step 3: Access device data via Geeny API

The final step is to implement a client for the Geeny Application Broker API in your application, which will allow it to access authorized device data. This process consists of three API calls.

To demonstrate the implementation of this API, we have provided the following code examples:

Get list of shards

When a Thing transmits data to the Geeny platform over a message stream, the messages are partitioned into shards. The first call to the Application Broker API will return a list of these shards. You can perform this call for one Message Type at a time.

Click here for the full documentation for this API call.

URL:

GET https://developers.geeny.io/ab/subscribe/{applicationId}/messageType/{messageTypeId}

Headers:

Authorization: Bearer <your-application-access-key>

Parameters:

Name Type In Description
applicationId string(UUID) path ID of your application.
messageType string(UUID) path ID of the Message Type to be queried.

Sample call using cURL:

curl -X GET \
https://developers.geeny.io/ab/subscribe/939e5db1-i02j-41cc-bb4d-718a2cf5e862/messageType/369c0532-4149-4e87-b98a-6d1eff2d0b98 \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9...'

Sample response:

{
    "shards": [
        {
            "shardId": "0"
        },
        {
            "shardId": "1"
        },
        {
            "shardId": "2"
        }
    ]
}

This will return an array of shards of the specified Message Type.

Create shard iterator

Next, create a shard iterator using the Application Broker API. The shard iterator will allow you to read messages of a specific Message Type sequentially.

Click here for the full documentation for this API call.

URL:

POST https://developers.geeny.io/ab/subscribe/{applicationId}/messageType/{messageTypeId}/iterator

Headers:

Authorization: Bearer <your-application-access-key>

Parameters:

Name Type In Description
messageType string(UUID) path ID of the Message Type to be queried.
shardId string body ID of the shard to be queried. Retrieved in the previous API call.
iteratorType string body Type of the iterator. Options include: LATEST, EARLIEST, AT_SEQUENCE_NUMBER, AFTER_SEQUENCE_NUMBER and LAST_CHECKPOINT.
startingSequenceNumber string(UUID) body (Optional) Use this parameter if you want to start reading from a specific message in the shard (at a specific sequence number).
maxBatchSize integer body Maximum number of messages from the shard to return (minimum 1, maximum 500).

Sample call using cURL:

curl -X POST \
  https://developers.geeny.io/ab/subscribe/939e5db1-i02j-41cc-bb4d-718a2cf5e862/messageType/369c0532-4149-4e87-b98a-6d1eff2d0b98/iterator \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9...' \
  -d '{
    "shardId": "0",
    "iteratorType": "LATEST",
    "maxBatchSize": 10
}'

Sample response:

{
    "shardIterator": "459c9b4b-32er-4635-b41f-1dec46ecf3b2"
}

Get messages from shard

Once you have created the iterator, you can use it to get individual data records of the given Message Type sent by Things.

Click here for the full documentation for this API call.

URL:

GET https://developers.geeny.io/ab/subscribe/{applicationId}/messageType/{messageTypeId}/iterator/{iteratorId}

Headers:

Authorization: Bearer <your-application-access-key>

Parameters:

Name Type In Description
applicationId string(UUID) path Your application ID.
messageTypeId string(UUID) path The ID of the Message Type to be queried.
iteratorId string(UUID) path ID of the iterator created in the previous step.

Sample call using cURL:

curl -X GET \
  https://developers.geeny.io/ab/subscribe/939e5db1-i02j-41cc-bb4d-718a2cf5e862/messageType/369c0532-4149-4e87-b98a-6d1eff2d0b98/iterator/459c9b4b-32er-4635-b41f-1dec46ecf3b2 \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9...'

Sample response:

{
  "messages": [
    {
      "shardId": "0",
      "messageId": "01928461-e97e-4207-af30-89d981247a8e",
      "payload": "ewogICAgICJ0aW1lIjogIjIwMDgtMDktMTVUMTU6NTM6MTAuMzI1KzA1OjAwIgp9",
      "sequenceNumber": "2",
      "thingId": "f2fc5495-f7fc-4218-9e16-ae1b955ee44e",
      "userId": "7bf1ca7a-2d1d-4108-98e4-dcee1fdf647b"
    },
    {
      "shardId": "0",
      "messageId": "01928461-e97e-4207-af30-89d981247a8e",
      "payload": "ewogICAgICJ0aW1lIjogIjIwMDgtMDktMTVUMTU6NTM6MTAuMzI1KzA1OjAwIgp9",
      "sequenceNumber": "3",
      "thingId": "f2fc5495-f7fc-4218-9e16-ae1b955ee44e",
      "userId": "7bf1ca7a-2d1d-4108-98e4-dcee1fdf647b"
    }
  ],
  "nextIterator": "77191c88-a34b-42cb-b353-0739b22273c1"
}

Receiving data via WebSocket push method

As alternative to polling messages using the Application Broker’s HTTP API, the Geeny platform offers a data push option based on WebSocket.

URL:

GET https://developers.geeny.io/ab/subscribe/{applicationId}/messageType/{messageTypeId}/ws?iteratorType={iteratorType}

Headers:

Authorization: Bearer <your-application-access-key>

Parameters:

Name Type In Description
applicationId string(UUID) path ID of your application.
messageType string(UUID) path ID of the Message Type to be queried.
iteratorType string query Type of the iterator. Options include: LATEST, EARLIEST

Sample calls using wscat:

Passing authorization token via header:

wscat --slash \
  -c https://developers.geeny.io/ab/subscribe/939e5db1-i02j-41cc-bb4d-718a2cf5e862/messageType/369c0532-4149-4e87-b98a-6d1eff2d0b98/ws?iteratorType=LATEST \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9...'

NOTE: Some WebSocket clients might not support specifying headers for establishing a connection. In this case, you can pass the authorization token via basic HTTP auth:

wscat --slash \
  -c https://developers.geeny.io/ab/subscribe/939e5db1-i02j-41cc-bb4d-718a2cf5e862/messageType/369c0532-4149-4e87-b98a-6d1eff2d0b98/ws?iteratorType=LATEST \
  --auth 'geeny:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9...'

Please note that we use geeny as the username and the application access key as the password.

The Application Broker also supports authorization via subprotocol for cases when a web browser is used and basic HTTP auth is not possble:

wscat --slash \
  -c https://developers.geeny.io/ab/subscribe/939e5db1-i02j-41cc-bb4d-718a2cf5e862/messageType/369c0532-4149-4e87-b98a-6d1eff2d0b98/ws?iteratorType=LATEST \
  --subprotocol 'authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9...'

Please note that subprotocol mimics authorization header semantics and consists of the authorization keyword, the authorization token type bearer (all lowercase), and the application access key itself, using the . symbol as a separator.

Sample response:

Messages will be pushed one by one and not as a batch, in contrast to polling the API.

  {
    "shardId": "0",
    "messageId": "01928461-e97e-4207-af30-89d981247a8e",
    "payload": "ewogICAgICJ0aW1lIjogIjIwMDgtMDktMTVUMTU6NTM6MTAuMzI1KzA1OjAwIgp9",
    "sequenceNumber": "2",
    "thingId": "f2fc5495-f7fc-4218-9e16-ae1b955ee44e",
    "userId": "7bf1ca7a-2d1d-4108-98e4-dcee1fdf647b"
  }

Parsing the response

As mentioned in step 2, when you make the last request to the Application Broker API, it will return all messages of that Message Type from all users that have authorized your application. You will need to filter the response with the Geeny user ID that you extracted from the Connect flow.

Step 4: Test data receiving with the Thing Emulator

We have an example Thing Type with a set of standardized resources that can be used to test data polling in your application.

First, you must create a Virtual Thing — i.e., an instance of a Thing Type that lives in our backend and can only be used by you. See step 5 of the Thing Providers guide for instructions on how to set this up. Be sure to choose Example Thing Type when creating your Virtual Thing.

Once you’ve made your Virtual Thing, click on its name in the Your Things section of the Developers Dashboard and select the Logs & Thing Emulator tab. Scroll down past the logs console to the section labeled Emulator:

Thing Emulator

In the left-hand console, you can test sending messages to the Geeny platform from the Virtual Thing (i.e., using pub resources). In the right-hand console, you can test sending commands to the Virtual Thing (i.e., using sub resources). Each message that you send to the Thing will appear in the logs console above.

Log messages

The messages that you send to the Geeny platform from this Virtual Thing will be keyed with your Geeny user ID. You can find this ID using the /auth/me endpoint of the Connect API. Simply input your username and password as credentials to the Swagger UI console (in the Authorize section in the top right) and it will return your Geeny user profile, including your user ID.

Your application will be automatically authorized to access messages from your own Virtual Things, so you can retrieve these messages using the API calls in the previous step.

Step 5: Sending commands to Things

Your application can send commands to Things over the publish endpoint of the Application Broker API.

Get Thing IDs

In order to send a command to a Thing, you must know its ID. Make the following call to the Thing Manager API in order to get the ID(s).

Click here for the full documentation for this API call.

URL:

GET https://labs.geeny.io/things/api/v1/things?thingType={thingTypeId}

Headers:

Parameters:

Name Type Required? Description
offset string(UUID) No Number by which to offset the list of Things.
limit string(UUID) No Maximum number of Things to be returned.
thingType string(UUID) No Restrict the response to one or more Thing Types by supplying their Thing Type IDs (comma separated).

Sample call using cURL:

curl -X GET \
  'https://labs.geeny.io/things/api/v1/things?thingType=28964763-3b15-493a-b54f-b58a1b93ee21' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9...'

Sample response:

{
    "meta": {
        "offset": 0,
        "limit": 50,
        "thingType": [
            "28964763-3b15-493a-b54f-b58a1b93ee21"
        ]
    },
    "data": [
        {
            "id": "e256d968-59b7-4988-8bc3-5d13c8567abe",
            "name": "Geeny Thing",
            "serial_number": "123AAA",
            "thing_type": "28964763-3b15-493a-b54f-b58a1b93ee21",
            "created": "2018-07-06T10:52:59.859Z"
        },
        {
            "id": "d515dea7-c855-4be4-ae66-ab375fadaec1",
            "name": "Unnamed thing",
            "serial_number": "Unknown serial number",
            "thing_type": "28964763-3b15-493a-b54f-b58a1b93ee21",
            "created": "2018-06-21T10:42:10.279Z"
        }
    ]
}

All Things that have been authorized to share data with your application will appear in the response, and the ID of each thing is returned as its id property.

Send command

This API call sends the command(s) to the Thing(s). Note that each Thing belongs to a specific user that has authorized your application, and the ID of this user must be supplied in the command.

Click here for the full documentation for this API call.

URL:

POST https://developers.geeny.io/ab/publish/{applicationId}/messageType/{messageTypeId}/messages

Headers:

  • Authorization: Bearer <your-application-token>
  • Content-Type: application/json

Parameters:

Name Type Required? Description
applicationId string(UUID) Yes ID of the application sending the command.
messageTypeId string(UUID) Yes ID of the Message Type used for sending the command.
messages array[Object] Yes Array of commands to be delivered to Things. Includes the payload (base64-encoded payload of the command), userId (user ID of the Thing owner), and thingId (ID of the Thing to receive this command).

Sample call using cURL:

curl -H "Content-Type: application/json" \
     -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9..." \
     -X POST \
     -d '{
            "messages": [
              {
                "payload": "ewogICJsaWdodE9uIjogInRydWUiCn0=",
                "userId": "7cb6c116-32d5-45c3-908f-6e7eb3660900",
                "thingId": "25f72b0f-10d0-4acd-848c-20bf0daa5f11"
              }
            ]
        }' \
    https://developers.geeny.io/ab/publish/939e5db1-i02j-41cc-bb4d-718a2cf5e862/messageType/d33afdf4-df21-4d1a-ae50-84d6d6bdfbe0/messages

Sample response:

{
    "deliveredMessageIds": [
        "939e5db1-f4d9-41cc-bb4d-718a2cf5e862-64389084-b528-4e40-ac71-b3cc7b64f29e-f43c544b-71cb-4fd1-aff1-589996ad27a7"
    ]
}

Conclusion

Now your application is fully configured to access device data of the types you specified above. Note that it will only be able to access this data when a consumer authorizes your application to do so.