Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

cot-lib

Package Overview
Dependencies
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cot-lib

Easily consume the City of Things platform data

  • 3.1.1
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
2
decreased by-33.33%
Maintainers
1
Weekly downloads
 
Created
Source

The City of Things client library will help you to connect to the City of Things backend. It uses the Web Linking RFC 5988 and interprets the Link header for you. This way you can let the library follow the next/prev/last pages for you.

npm npm

Installation

npm install cot-lib --save

Usage & authentication

Typescript

This library is written in Typescript before being transpiled to Javascript, hence the type information is embedded. (Credentials are optional)

import { CotClient, LocationsClient, SourcesClient, Util } from 'cot-lib';

let credentials = {username: "user", password: "pass"};
let client = new CotClient('http://my-cot-backend.eu', credentials);
let hash = Util.encodeAsGeohash(31.123456,15.321654);

Javascript

This library can also be used as a regular javascript library. (Credentials are optional)

var CotClient = require('cot-lib').CotClient;
var Util = require('cot-lib').Util;

var credentials = {username: "user", password: "pass"};
var client = new CotClient('http://my-cot-backend.eu', credentials);
var hash = Util.encodeAsGeohash(31.123456,15.321654);

or

var cot = require('cot-lib');

var credentials = {username: "user", password: "pass"};
var client = new cot.CotClient('http://my-cot-backend.eu', credentials);
var hash = cot.Util.encodeAsGeohash(31.123456,15.321654);

Creating a CotClient

You start by creating a CotClient object. A CotClient object allows you to request the basic API functions. It needs a reference to the base url of the API.

Basic Auth credentials can be given as an extra optional argument.

import { CotClient } from 'cot-lib';
let credentials = {username: "user", password: "pass"};
let cotClient = new CotClient('http://my-cot-backend.eu', credentials);

Creating a SourcesClient

A SourcesClient object allows you to pre-define all the sourceIds you want to request data from simultaneously. The best way to create one, is from an existing CotClient.

import { CotClient, SourcesClient } from 'cot-lib';
let cotClient = new CotClient('http://my-cot-backend.eu', {username: "user", password:"pass"});
let sourcesClient = cotClient.createSourcesClient('sourceId1', 'sourceId2', 'sourceId3');

Creating a LocationsClient

A LocationsClient object allows you to pre-define all the geohashes you want to request data from simultaneously. Because of the sheer amount of data, you are required to already filter on the Type you are interested in. The best way to create one, is from an existing CotClient.

import { CotClient, LocationsClient } from 'cot-lib';
let cotClient = new CotClient('http://my-cot-backend.eu',  {username: "user", password:"pass"});
let locationsClient = cotClient.createLocationsClient('u15kk', 'u15kh', 'u15ke');

About Observables

This API makes heavy use of ReactiveX Observables. They are a very modern way to do asynchronous communication. When calling subscribe(...) on an Observable, the Observable is activated and starts its work. It will asynchronously notify its different handlers. The first handler - typically called next - can be notified multiple times, everytime there is new data available, the second one handles errors and the last one is called when the Observable stream has completed its work.

Simple use of Observables

The simplest way to use them is as follows. Given a method getMyData() that returns an Observable<MyData> type. This is how you handle it:

Typescript

client.getMyData().subscribe(
    nextData => { 
        // handle nextData as its coming in, this handler will be called on every update with new data
    },
    error => {
        // do something when an error occurs
    },
    () => {
        // this handler will be called when the data streaming is complete and there is no more incoming data
    }
);

Javascript

client.getMyData().subscribe(
    function(nextData) { 
        // handle nextData as its coming in, this handler will be called on every update with new data
    },
    function(error) {
        // do something when an error occurs
    },
    function() {
        // this handler will be called when the data streaming is complete and there is no more incoming data
    }
);

There are many more things you can do with Observables, for a more comprehensive guide we refer to the ReactiveX introduction website and the RxJs github page with its excellent Readme.

What about Promises?

An Observable allows you to call the toPromise() method on it, after which it can be handled as a normal Promise with a then(...) method. Be aware though that to first argument callback of the then(...) method will only be called with the very last next update of the observable. So this will not always behave as you would expect.

However we remediated this with two Util methods collectOne(...) and collectMultiple(...) that are further explained in the API section. They allow for usage that is more in line with the Promises workflow.

Types

The API uses a couple of Types that it returns.

Type

A Type object describes sources of the same type. It has an id to uniquely identify it. It has a finalizationDelay that determines the delay until the data is considered unchanged and indefinitely cacheable, it has a preferredGranularity that determines the default size of returned TemperalPage brackets for Sources of this Type. At last is has a schema that defines the structure and meaning of the fields in the Source data.

{
    "id": "bpost.car",
    "finalizationDelay": 0,
    "preferredGranularity": "HOURLY",
    "schema": {
      "co2": "IntNumber (The co2 level.)"
    }
}
  

Source

A Source represents a sensor, actuator or data producer of some sort. It has an id to uniquely identify it. It has a name which is a human readable label for this Source. At last it has a typeRefs field which contains a set of typeId strings that define the Types this Source belongs to.

{
    "id": "Car1",
    "name": "Bpost Mockup Car 1",
    "typeRefs": [
      "bpost.car"
    ]
}

TemporalPage

A TemporalPage object is a bucket (like a page in a pageing mechanism, but spread by time instead of amount). This object contains the parsed Link header values, so they can easily be accessed.

{
    "data": {TemporalPageData},
    "link": {TemporalPageLink}
}

TemporalPageData

A TemporalPageData object is just the data part of a TemporalPage. It is used when the TemporalPageLink field is no longer relevant in the returned data of a TemporalPage object. (e.g. when requesting data of an interval of multiple pages). (note that next, prev and last fields are optional and not always present).

{
    "name": "Car1" or ["Car1", "Car2"],
    "columns": ["timestamp","co2","temperature"],
    "values": [
        [1483201200, 430, 297.15],
        [1483201202, 432, 297.13],
        [1483201212, 433, 300.01],
        [1483201301, 427, 301.14],
        [1483201302, 419, 298.06],
        [1483201331, 418, 299.48],
        [1483201340, 424, 299.82],
    ]
}

A TemporalPageLink object contains the parsed Link header values relevant for the City of Things client to request follow up requests. It parses the Link header according to the RFC 5988 specification.

{
    "self": "/sources/Car1/events/20161231/16?from=1483201200",
    "next": "/sources/Car1/events/20161231/17",
    "prev": "/sources/Car1/events/20161231/16?to=1483201200",
    "last": "/sources/Car1/events/20161231/20?to=1483215300",
}

CotClient API

CotClient(host: string, credentials?: CotClientCredentials): CotClient

Constructor, call as new CotClient('http://my-cot.backend.eu', {username: "user", password: "pass"}). This will construct a new CotClient object to work with.

cotClient.getTypes(): Observable<Type[]>

Returns an Observable containing an array with all available Type objects.

cotClient.getType(typeId: string): Observable<Type>

Returns an Observable containing Type information of the Type with the given typeId.

cotClient.getSourcesOf(typeId: string): Observable<Source[]>

Returns an Observable containing an array of Source objects belonging to the Type with the given typeId.

cotClient.getSources(): Observable<Source[]>

Returns an Observable containing an array of all Source objects currently available.

cotClient.getSource(sourceId: string): Observable<Source>

Returns an Observable containing the Source object with the given sourceId.

cotClient.pollData(sourceId: string, period: number, from?: number): Observable<TemporalPage>

Continuously poll for data from a Source defined by a given sourcId. The period field is the time in milliseconds in between polling for new values. The optional from argument is the UNIX UTC timestamp from which to start polling. If not present the last data will be polled.

cotClient.getDataInterval(sourceId: string, from: number, to: number): Observable<TemporalPageData>

Returns an Observable containing a TemporalPageData object with data from a Source defined by a given sourceId. The TemporalPageData contains the aggregated interval. This method automatically calls the necessary subsequent requests. On every response, the Observable calls its next handler with the newly received data. It is up to the developer to listen for this incoming data and update the already received data.

If you want to wait and only call a handler when all data has come in, use the Util.collectOne(...) method on this Observable. More information on this method can be found at the end of this API section.

The arguments from and to are UNIX (UTC) timestamps.

cotClient.pollDataIn(geohash: string, typeId: string, period: number, from?: number): Observable<TemporalPage>

Continuously poll for data in a location, defined by the geohash and belonging to a given typeId. The period field is the time in milliseconds in between polling for new values. The optional from argument is the UNIX UTC timestamp from which to start polling. If not present the last data will be polled.

cotClient.getDataIntervalIn(geohash string, typeId: string, from: number, to: number): Observable<TemporalPageData>

Returns an Observable containing a TemporalPageData object with data from Sources belonging to a given typeId, within the given geohash. The TemporalPageData contains the aggregated interval. This method automatically calls the necessary subsequent requests. On every response, the Observable calls its next handler with the newly received data.

It is up to the developer to listen for this incoming data and update the already received data!

If you want to wait and only call a handler when all data has come in, use the Util.collectOne(...) method on this Observable. More information on this method can be found at the end of this API section.

The arguments from and to are UNIX (UTC) timestamps.

cotClient.createSourcesClient(...sourceIds: string[]): SourcesClient

A convenience method to create a new SourcesClient object, by reusing the host and credential settings from the CotClient.

cotClient.createLocationsClient(...sourceIds: string[]): LocationsClient

A convenience method to create a new LocationsClient object, by reusing the host and credential settings from the CotClient.

SourcesClient API

SourcesClient(host: string, axiosInstance: AxiosInstance, ...sourceIds: string[]): SourcesClient

Recommended: use cotClient.createSourcesClient(...sourceIds)

Constructor, call as new SourcesClient('http://my-cot.backend.eu', null, 'sourceId1','sourceId2', 'sourceId3'). This will construct a new sourcesClient to work with. (The axiosInstance is an instance of the internally used axios library to perform requests, if null the default is used).

sourcesClient.pollData(period: number, from?: number): Observable<TemporalPage>

Poll for data of each Source defined in the client. The period field is the time in milliseconds in between polling for new values. Every update will immediatly be sent through, hence it is mandatory to check the incoming data for the key. The optional from argument is the UNIX UTC timestamp from which to start polling. If not present the last data will be polled.

sourcesClient.getDataInterval(sourceId: string, from: number, to: number): Observable<TemporalPageData>

Returns an Observable containing a TemporalPageData object with data from all Source defined by the registered sourceIds of this sourcesClient. The TemporalPageData contains the aggregated interval. This method automatically calls the necessary subsequent requests. On every response, the Observable calls its next handler with the newly received data.

It is up to the developer to listen for this incoming data and update the already received data!

If you want to wait and only call a handler when all data has come in, use the Util.collectMany(...) method on this Observable. More information on this method can be found at the end of this API section.

The arguments from and to are UNIX (UTC) timestamps.

LocationsClient API

LocationsClient(host: string, ...geohashes: string[]): LocationsClient

Recommended: use cotClient.createLocationsClient(...geohashes)

Constructor, call as new LocationsClient('http://my-cot.backend.eu', null, 'geohash1','geohash2', 'geohash3'). This will construct a new LocationsClient to work with. (The axiosInstance is an instance of the internally used axios library to perform requests, if null the default is used).

locationsClient.pollData(typeId: string period: number, from?: number): Observable<TemporalPage>

Poll for data from each location, defined in the client by geohashes, filtered by the Type given by the typeId arugment. The period field is the time in milliseconds in between polling for new values. Every update will immediatly be sent through, hence it is mandatory to check the incoming data for the key. The optional from argument is the UNIX UTC timestamp from which to start polling. If not present the last data will be polled.

locationsClient.getDataInterval(typeId: string, from: number, to: number): Observable<TemporalPageData>

Returns an Observable containing a TemporalPageData object with data from all locations defined by the registered geohashes of this locationsClient. Because of the sheer amount of data, a typeId must be given to limit the results to Sources from this Type. The TemporalPageData contains the aggregated interval. This method automatically calls the necessary subsequent requests. On every response, the Observable calls its next handler with the newly received data.

It is up to the developer to listen for this incoming data and update the already received data!

If you want to wait and only call a handler when all data has come in, use the Util.collectMany(...) method on this Observable. More information on this method can be found at the end of this API section.

The arguments from and to are UNIX (UTC) timestamps.

Util API

The Util class contains some static methods that can be helpful when working with the City of Things cilent library.

Util.timestampOf(year: number, month: number, day?: number, hours?: number, minutes?: number, seconds?: number, milliseconds?: number): number

Returns the unix (UTC) timestamp for the given date parameters. The arguments are considered to be in UTC time.

ArgumentOptionalDescription
yearnoFour digit number
monthnoThe month in the year (1-12)
dayyesThe day of the month (1-31)
hoursyesThe hour of the day (0-23)
minutesyesThe minute of the day (0-59)
secondsyesThe seconds of the day (0-59)
millisecondsyesThe milliseconds of the day (0-999)

Util.encodeAsGoehash(lat: number, lng: number, precision: number = 9): string

Encodes a latitude-longitude point as a geohash with the given precision.

ArgumentDescription
latLatitude of point
lngLongitude of point
precisionCharacter length of geohash (defaults to 9)

Util.decodeFromGeohash(geohash: string): {"latitude": number, "longitude": number}

Decode a given geohash as a latitude-longitude point.

Util.collectOne(observable: Observable<TemporalPageData>, callback: (data: TemporalPageData) => void, error?: (error: Error) => void): void

This utility method will subscribe to an Observable<TemporalPageData> and collect the results that are sent through on each update of the next handler. Once it is complete, the callback handler will be called with the complete collected data as an argument. An optional error handler is called with the Error object, if one occurs.

Note: Use this in conjunction with CotClient getDataInterval methods.

import { CotClient, Util } from 'cot-lib';

testMethod() {
    let client = new CotClient('http://my-cot-endpoint.eu');
    let from = Util.timestampOf(2017, 3, 1, 0, 0, 0, 0);
    let to = Util.timestampOf(2017, 4, 1, 0, 0, 0, 0);
    let observable = client.getDataIntervalIn('u15kk', 'bpost.cars', from, to);

    Util.collectOne(observable, temporalPageData => {
      console.log(temporalPageData);
    });
  }

Util.collectMany(observable: Observable<TemporalPageData>, callback: (data: TemporalPageData[]) => void, error?: (error: Error) => void): void

This utility method will subscribe to an Observable<TemporalPageData> and collect the results that are sent through on each update of the next handler for each endpoint. It will send these updates as an array of TemporalPageData objects. Once it is complete, the callback handler will be called with the complete collected data as an argument, this is again an array of TemporalPageData objects, as many as there are registered sourceIds for a SourcesClient or geohashes for a LocationsClient. An optional error handler is called with the Error object, if one occurs.

Note: Use this in conjunction with SourcesClient and LocationsClient getDataInterval methods.

import { SourcesClient, Util } from 'cot-lib';

testMethod() {
    let sclient = new SourcesClient('http://my-cot-endpoint.eu', 'Car1', 'Car2', 'Car3', 'Car4');
    let from = Util.timestampOf(2017, 3, 1, 0, 0, 0, 0);
    let to = Util.timestampOf(2017, 4, 1, 0, 0, 0, 0);
    let observable = sclient.getDataInterval(from, to);

    Util.collectMany(observable, collectedDataArray => {
      collectedDataArray.forEach(temporalPageData => {
        console.log(temporalPageData);
      });
    });
  }

Keywords

FAQs

Package last updated on 10 May 2017

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc