Assets - iothink integration and authentification
MODIFY
src/integration/asset/AssetFactory.ts
src/integration/asset/AssetFactory.ts
@@ -2,6 +2,7 @@ import { AssetConnectionType, AssetSetting } from '../../types/Setting';
import AssetIntegration from './AssetIntegration';
import GreencomAssetIntegration from './greencom/GreencomAssetIntegration';
+import IothinkAssetIntegration from './iothink/IothinkAssetIntegration';
import Logging from '../../utils/Logging';
import SchneiderAssetIntegration from './schneider/SchneiderAssetIntegration';
import { ServerAction } from '../../types/Server';
@@ -33,11 +34,14 @@ export default class AssetFactory {
case AssetConnectionType.GREENCOM:
assetIntegrationImpl = new GreencomAssetIntegration(tenantID, settings.asset, foundConnection);
break;
+ case AssetConnectionType.IOTHINK:
+ assetIntegrationImpl = new IothinkAssetIntegration(tenantID, settings.asset, foundConnection);
+ break;
}
return assetIntegrationImpl;
}
}
- Logging.logDebug({
+ await Logging.logDebug({
tenantID: tenant.id,
action: ServerAction.ASSET,
module: MODULE_NAME, method: 'getAssetImpl',

ADD
src/integration/asset/iothink/IothinkAssetIntegration.ts
+import { AssetConnectionSetting, AssetSetting } from '../../../types/Setting';
+
+import { AbstractCurrentConsumption } from '../../../types/Consumption';
+import Asset from '../../../types/Asset';
+import AssetIntegration from '../AssetIntegration';
+import AxiosFactory from '../../../utils/AxiosFactory';
+import { AxiosInstance } from 'axios';
+import BackendError from '../../../exception/BackendError';
+import Constants from '../../../utils/Constants';
+import Cypher from '../../../utils/Cypher';
+import Logging from '../../../utils/Logging';
+import { ServerAction } from '../../../types/Server';
+import Utils from '../../../utils/Utils';
+
+const MODULE_NAME = 'IothinkAssetIntegration';
+
+export default class IothinkAssetIntegration extends AssetIntegration<AssetSetting> {
+ private axiosInstance: AxiosInstance;
+
+ public constructor(tenantID: string, settings: AssetSetting, connection: AssetConnectionSetting) {
+ super(tenantID, settings, connection);
+ this.axiosInstance = AxiosFactory.getAxiosInstance(tenantID);
+ }
+
+ public async checkConnection(): Promise<void> {
+ await this.connect();
+ }
+
+ public async retrieveConsumptions(asset: Asset): Promise<AbstractCurrentConsumption[]> {
+ // Set new Token
+ const token = await this.connect();
+ const request = `${this.connection.url}/${asset.meterID}`;
+ try {
+ // Get consumption
+ const response = await this.axiosInstance.get(
+ request,
+ {
+ headers: this.buildAuthHeader(token)
+ }
+ );
+ await Logging.logDebug({
+ tenantID: this.tenantID,
+ source: Constants.CENTRAL_SERVER,
+ action: ServerAction.RETRIEVE_ASSET_CONSUMPTION,
+ message: `${asset.name} > Iothink web service has been called successfully`,
+ module: MODULE_NAME, method: 'retrieveConsumption',
+ detailedMessages: { response: response.data }
+ });
+ return this.filterConsumptionRequest(asset, response.data);
+ } catch (error) {
+ throw new BackendError({
+ source: Constants.CENTRAL_SERVER,
+ module: MODULE_NAME,
+ method: 'retrieveConsumption',
+ action: ServerAction.RETRIEVE_ASSET_CONSUMPTION,
+ message: 'Error while retrieving the asset consumption',
+ detailedMessages: { request, token, error: error.message, stack: error.stack, asset }
+ });
+ }
+ }
+
+
+ private filterConsumptionRequest(asset: Asset, data: any[]): AbstractCurrentConsumption[] {
+ const consumption = {} as AbstractCurrentConsumption;
+ return [consumption];
+ }
+
+
+ private async connect(): Promise<string> {
+ // Check if connection is initialized
+ this.checkConnectionIsProvided();
+ // Get credential params
+ const credentials = await this.getCredentialURLParams();
+ // Send credentials to get the token
+ const response = await Utils.executePromiseWithTimeout(5000,
+ this.axiosInstance.post(`${this.connection.url}/token`,
+ credentials,
+ {
+ // @ts-ignore
+ 'axios-retry': {
+ retries: 0
+ },
+ headers: this.buildFormHeaders()
+ }),
+ `Time out error (5s) when getting the token with the connection URL '${this.connection.url}/token'`
+ );
+ // Return the Token
+ return response.data.access_token;
+ }
+
+ private async getCredentialURLParams(): Promise<URLSearchParams> {
+ const params = new URLSearchParams();
+ params.append('grant_type', 'password');
+ params.append('username', this.connection.iothinkConnection.user);
+ params.append('password', await Cypher.decrypt(this.tenantID, this.connection.iothinkConnection.password));
+ return params;
+ }
+
+ private checkConnectionIsProvided(): void {
+ if (!this.connection) {
+ throw new BackendError({
+ source: Constants.CENTRAL_SERVER,
+ module: MODULE_NAME,
+ method: 'checkConnectionIsProvided',
+ action: ServerAction.CHECK_CONNECTION,
+ message: 'No connection provided'
+ });
+ }
+ }
+
+ private buildFormHeaders(): any {
+ return {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ };
+ }
+
+ private buildAuthHeader(token: string): any {
+ return {
+ 'Authorization': 'Bearer ' + token
+ };
+ }
+}

MODIFY
src/server/rest/v1/service/security/SettingSecurity.ts
src/server/rest/v1/service/security/SettingSecurity.ts
@@ -222,6 +222,12 @@ export default class SettingSecurity {
clientSecret: sanitize(connection.greencomConnection.clientSecret),
};
break;
+ case AssetConnectionType.IOTHINK:
+ sanitizedConnection.iothinkConnection = {
+ user: sanitize(connection.iothinkConnection.user),
+ password: sanitize(connection.iothinkConnection.password),
+ };
+ break;
}
settings.content.asset.connections.push(sanitizedConnection);
}

MODIFY
src/types/Setting.ts
src/types/Setting.ts
@@ -277,11 +277,13 @@ export interface AssetConnectionSetting {
type: AssetConnectionType;
schneiderConnection?: AssetSchneiderConnectionType;
greencomConnection?: AssetGreencomConnectionType;
+ iothinkConnection?: AssetIothinkConnectionType;
}
export enum AssetConnectionType {
SCHNEIDER = 'schneider',
- GREENCOM = 'greencom'
+ GREENCOM = 'greencom',
+ IOTHINK = 'iothink'
}
export interface AssetUserPasswordConnectionType {
@@ -298,6 +300,10 @@ export interface AssetGreencomConnectionType {
export interface AssetSchneiderConnectionType extends AssetUserPasswordConnectionType {
}
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface AssetIothinkConnectionType extends AssetUserPasswordConnectionType {
+}
+
export enum CarConnectorSettingsType {
CAR_CONNECTOR = 'carConnector',
}

Assets - iothink integration and authentification