Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
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.
Statistics api is added and the old code has been restructured and optimized for minimal code duplication. The old v3 documentation can still be found at the bottom of the page.
New features added:
npm install cot-lib --save
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.Geohash.encode(31.123456,15.321654);
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.Geohash.encode(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.Geohash.encode(31.123456,15.321654);
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);
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 (or onNext) - 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.
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.
Beware: 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.
The API uses a couple of Types that it returns.
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.)"
}
}
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"
]
}
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.
{
"link": {TemporalPageLink},
"data": {Bucket | StatsUnit | StatsBatch}
}
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. (note that next, prev and last fields are optional and not always present).
{
"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",
}
A Bucket object is just the data part of a TemporalPage. It is used as a direct return type 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).
{
"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 StatsUnit object is just the data part of a TemporalPage. It is used as a direct return type 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).
{
"columns": ["mean", "min", "max", "stddev"],
"count": 53,
"values": {
"co2": [503.65, 489, 513, 1.1],
"t": [21.4, 8.2, 32.1, 4.123]
}
}
A StatsBatch object is just the data part of a TemporalPage. It is used as a direct return type 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).
{
"columns": ["mean", "min", "max", "stddev"],
"bins": 24,
"count": [20, 15, 0, 0, 0, 35, 21, 49, 63, 52, 53, 68, 45, 55, 50, 51, 52, 51, 53, 53, 49, 55, 52, 52], // length == bins
"values": {
"co2": [
[503.65, 489, 513, 1.1],
[502.61, 489, 563, 5.2],
//...
[468.65, 425, 515, 0.51]
], // length == bins
"t": [
[19.4, 8.2, 24.1, 4.123],
[21.1, 8.2, 32.1, 3.13],
//...
[10.3, 8.2, 12.1, 0.23]
] // length == bins
}
}
Constructor, call as new CotClient('http://my-cot.backend.eu', {username: "user", password: "pass"})
. This will construct a new CotClient object to work with.
Returns an Observable containing an array with all available Type objects.
Returns an Observable containing Type information of the Type with the given typeId.
Returns an Observable containing an array of Source objects belonging to the Type with the given typeId.
Returns an Observable containing an array of all Source objects currently available.
Returns an Observable containing the Source object with the given sourceId.
Returns a MultiClient that internally iterates over all given sourceIds when requesting data or stats. For methods see MultiClient API
Returns a MultiClient that internally iterates over all given geohashes of a given type when requesting data or stats. For methods see MultiClient API
A multiclient is a common structure for getting data and statistics from the client, no matter if you target one or more sources, or one or more locations (of a given type).
Operation | Operation chain 1 | Operation chain 2 | Return | Description |
---|---|---|---|---|
.getData() | Request data | |||
.latest() | Observable<TemporalPage> | Request the latest available data. | ||
.poll(period, fromTS?) | Observable<TemporalPage> | Continuously poll the data | ||
.range(fromTS, toTS) | Observable<Bucket> | Request a range of data, bucket by bucket | ||
.getStats() | Request statistics | |||
.getUnit() | Request statistics in units (day/hour) | |||
.getHour(hourTS) | Observable<TemporalPage> | Get statistics unit for a single hour | ||
.getHourRange(fromTS, toTS) | Observable<TemporalPage> | Get statistics units for a range of hours, one after the other | ||
.getHourRecap(fromTS, toTS) | Observable<StatsUnit> | Get a single statistics hour unit as a recap representing the requested range | ||
.getHourRecapOf(hourTS[]) | Observable<StatsUnit> | Get a single statistics hour unit as a recap representing the requested hours. | ||
.getDay(dayTS) | Observable<TemporalPage> | Get statistics unit for a single day | ||
.getDayRange(fromTS, toTS | Observable<TemporalPage> | Get statistics units for a range of days, one after the other | ||
.getDayRecap(fromTS, toTS) | Observable<StatsUnit> | Get a single statistics day unit as a recap representing the requested range | ||
.getDayRecapOf(dayTS[]) | Observable<StatsUnit> | Get a single statistics day unit as a recap representing the requested days. | ||
.getBatch() | Request statistics in batch form (complete day filled with hour bins) | |||
.getDay(dayTS) | Observable<TemporalPage> | Get statistics batch for a single day | ||
.getDayRange(fromTS, toTS) | Observable<TemporalPage> | Get statistics batches for a range of days, one after the other | ||
.getDayRecap(fromTS, toTS) | Observable<StatsBatch> | Get a single statistics day batch as a recap representing the requested range | ||
.getDayRecapOf(dayTS[]) | Observable<StatsBatch> | Get a single statistics day batch as a recap representing the requested days. |
The Util namespace contains some static methods that can be helpful when working with the City of Things cilent library. They are structured in exposed static classes.
Encodes a latitude-longitude point as a geohash with the given precision.
Decode a given geohash as a latitude-longitude point.
Returns the unix (UTC) timestamp for the given date parameters. The arguments are considered to be in UTC time.
Argument | Optional | Description |
---|---|---|
year | no | Four digit number |
month | no | The month in the year (1-12) |
day | yes | The day of the month (1-31) |
hours | yes | The hour of the day (0-23) |
minutes | yes | The minute of the day (0-59) |
seconds | yes | The seconds of the day (0-59) |
milliseconds | yes | The milliseconds of the day (0-999) |
Returns the string representation that can be used in the REST api urls. (eg. 20171205 for December 5 2017)
Returns the string representation that can be used in the REST api urls.(eg. 13 for 1pm)@param timestamp The UTC timestamp to convert
Returns an array of 7 string arrays (mon-sun). Each array contains the UTC timestamps for each instance of that weekday in the month.
[deprecated]
Constructor, call as new CotClient('http://my-cot.backend.eu', {username: "user", password: "pass"})
. This will construct a new CotClient object to work with.
Returns an Observable containing an array with all available Type objects.
Returns an Observable containing Type information of the Type with the given typeId.
Returns an Observable containing an array of Source objects belonging to the Type with the given typeId.
Returns an Observable containing an array of all Source objects currently available.
Returns an Observable containing the Source object with the given sourceId.
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.
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.
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.
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.
A convenience method to create a new SourcesClient object, by reusing the host and credential settings from the CotClient.
A convenience method to create a new LocationsClient object, by reusing the host and credential settings from the CotClient.
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).
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.
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.
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).
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.
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.
The Util class contains some static methods that can be helpful when working with the City of Things cilent library.
Returns the unix (UTC) timestamp for the given date parameters. The arguments are considered to be in UTC time.
Argument | Optional | Description |
---|---|---|
year | no | Four digit number |
month | no | The month in the year (1-12) |
day | yes | The day of the month (1-31) |
hours | yes | The hour of the day (0-23) |
minutes | yes | The minute of the day (0-59) |
seconds | yes | The seconds of the day (0-59) |
milliseconds | yes | The milliseconds of the day (0-999) |
Encodes a latitude-longitude point as a geohash with the given precision.
Argument | Description |
---|---|
lat | Latitude of point |
lng | Longitude of point |
precision | Character length of geohash (defaults to 9) |
Decode a given geohash as a latitude-longitude point.
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);
});
}
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);
});
});
}
FAQs
Easily consume the City of Things platform data
The npm package cot-lib receives a total of 56 weekly downloads. As such, cot-lib popularity was classified as not popular.
We found that cot-lib demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
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.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.