UNPKG

thingsboard_api

Version:

Thingsboard REST API implementation

415 lines (383 loc) 14.7 kB
const fetch = require('node-fetch'); const axios = require('axios'); const get = require('./get.js'); const possibleEntityTypes = { device: 'DEVICE', asset: 'ASSET', view: 'ENTITY_VIEW', }; /** * @param {String} customType Such as Mobile, PC, not asset/device * @param {String} entityType asset/device/entity_vew * @param {String} attributes If exist - push to new object * @param {String} parentName for entity_view - required, for other - "inheritance" * @param {String} parentType for entity_view - required(asset,device), for other - "inheritance" * @param {String} parentKeys for entity_view - required(server_scope keys only), for other - "inheritance"(override) if null - try to get all parent's keys * @param {String} parentRelation boolean - calls createRelation */ async function createEntity(name, customType, attributes = null, entityType, parentName, parentType, parentKeys = null, parentRelation = null) { // check only two params name or type if (((typeof name === 'undefined') || (name === null)) || ((typeof customType === 'undefined') || (customType === null))) { return { error: true, message: 'createEntity(), Error: name or type are not defined or null' }; } if (parentKeys != null && !Array.isArray(parentKeys)) { if (parentKeys.indexOf(',') !== -1) { parentKeys = parentKeys.split(','); } else { parentKeys = [parentKeys]; } } if (parentKeys !== false && parentKeys !== null) { const parentAttributes = await get.objectIDandKeys(parentName, parentType); if (parentAttributes.error) { return { error: true, message: parentAttributes.message }; } for (const key in parentAttributes) { if (key === 'id' || key === 'name' || key === 'type') { continue; } attributes[key] = parentAttributes[key]; } } let url = ''; switch (entityType.toUpperCase()) { case possibleEntityTypes.device: url = `http://${process.env.TB_HOST}:${process.env.TB_PORT}/api/device`; break; case possibleEntityTypes.asset: url = `http://${process.env.TB_HOST}:${process.env.TB_PORT}/api/asset`; break; case possibleEntityTypes.view: { const ans = await createEntityView(name, customType, attributes, parentName, parentType, parentKeys, parentRelation); return ans; } default: return { error: true, message: `Get unknown entityType: ${entityType}` }; } const body = { name: name, type: customType, }; try { const post = await fetch(url, { method: 'post', body: JSON.stringify(body), headers: { 'Content-Type': 'application/json', 'X-Authorization': `Bearer ${process.env[tokenRand+'TB_TOKEN']}`, }, }); const response = await post.json(); if (typeof response === 'undefined') { return { error: true, message: 'Create entity response is not defined or null' }; } if (response.status === 400) { return { error: true, message: `Create entity error: ${response.message} ` }; } if (attributes == null && (!parentRelation || parentRelation == null)) { return response.id.id; } // Далее идём только если нужно пушить аттрибуты или создавать отношение const { id } = response.id; let statusRelation = false; let statusAttributes = false; if (parentRelation) statusRelation = await createRelation(name, entityType, parentName, parentType); if (attributes != null || parentKeys != null) { statusAttributes = await pushAttributes(name, entityType, attributes); } const answer = { id, statusAttributes, statusRelation, }; return answer; } catch (err) { return { error: true, message: `createEntity(), While creating entity error: ${err}` }; } } /** * @param {String} type Such as Mobile, PC, not asset/device * @param {String} attributes If exist - push to new object * @param {String} parentName for entity_view - required, for other - "inheritance" * @param {String} parentType for entity_view - required(asset,device), for other - "inheritance" * @param {String} parentKeys for entity_view - required(server_scope keys only), for other - "inheritance"(override) if null - try to get all parent's keys * @param {String} parentRelation boolean - calls createRelation */ async function createEntityView(name, type, attributes = null, parentName, parentType, parentKeys, parentRelation = false) { // check only two params name or type! Maybe extends in future! if (((typeof name === 'undefined') || (name === null)) || ((typeof type === 'undefined') || (type === null)) || ((typeof parentName === 'undefined') || (parentName === null)) || ((typeof parentType === 'undefined') || (parentType === null))) { return { error: true, message: 'createEntityView(), Error: name or type; or parentName or parentType are not defined or null' }; } parentType = parentType.toUpperCase(); const url = `http://${process.env.TB_HOST}:${process.env.TB_PORT}/api/entityView`; let body = {}; try { body = { keys: { timeseries: [], attributes: { ss: parentKeys, // Какие аттрибуты берем cs: [], sh: [], }, }, endTimeMs: 0, startTimeMs: 0, name, // Имя представления type, // Тип представления entityId: { entityType: parentType, // от какого типа берем аттрибуты ASSET/DEVICE id: await get.objectID(parentName, parentType), // От кого берем аттрибуты }, }; } catch (err) { return { error: true, message: `createEntityView(), Error: ${err}` }; } try { const response = await axios(url, { method: 'post', data: JSON.stringify(body), headers: { 'Content-Type': 'application/json', 'X-Authorization': `Bearer ${process.env[tokenRand+'TB_TOKEN']}`, }, }); // new entity_view id const payload = response.data.id.id; if (payload.length === 0) { return { error: true, message: 'createEntityView(), Error while creating new entity_view! ' }; } if (attributes == null && (!parentRelation || parentRelation == null)) { return payload; } // Далее идём только если нужно пушить аттрибуты или создавать отношение const id = payload; let statusRelation = false; let statusAttributes = false; if (parentRelation) { statusRelation = await createRelation(name, 'entity_view', parentName, parentType); // error while creating relations! if (statusRelation.error) { return { error: true, message: statusRelation.message }; } } if (attributes !== null) { statusAttributes = await pushAttributes(name, 'entity_view', attributes); // error while pushing attributes! if (statusAttributes.error) { return { error: true, message: statusAttributes.message }; } } const answer = { id, statusAttributes, statusRelation, }; return answer; } catch (err) { return { error: true, message: `createEntityView(), Error: ${err}` }; } } async function createRelation(name, entity_type, parentName, parentType,id=null,parentId=null) { //if (((typeof name === 'undefined') || (name === null)) || ((typeof entity_type === 'undefined') || (entity_type === null)) // || ((typeof parentName === 'undefined') || (parentName === null)) || ((typeof parentType === 'undefined') || (parentType === null))) { // return { error: true, message: 'createRelation(), Error: name or type; or parentName or parentType are not defined or null' }; // } // to - child, from - parent const url = `http://${process.env.TB_HOST}:${process.env.TB_PORT}/api/relation`; let body = {}; if(id === null) id = await get.objectID(name, entity_type) if(parentId === null) parentId = await get.objectID(parentName, parentType) try { body = { to: { entityType: entity_type.toUpperCase(), id: id, }, from: { entityType: parentType.toUpperCase(), id: parentId, }, type: 'Contains', }; } catch (err) { return { error: true, message: `createRelation(), Error: ${err}` }; } if (JSON.stringify(body) === '{}') { return { error: true, message: 'createRelation(), Error: empty request object for relation creation!' }; } try { const response = await axios(url, { method: 'post', data: JSON.stringify(body), headers: { 'Content-Type': 'application/json', 'X-Authorization': `Bearer ${process.env[tokenRand+'TB_TOKEN']}`, }, }); if (response.data === '') { return { success: true }; } } catch (err) { return { error: true, message: `createRelation(), Error: ${err}` }; } } async function pushAttributes(name = null, entityType = null, attributes = null, telemetry = null, ts = null, deviceToken = null, objectId = null) { // Push telemetry by token // Works only for devices! if (deviceToken != null && entityType.toUpperCase() === 'DEVICE') { const url = `http://${process.env.TB_HOST}:${process.env.TB_PORT}/api/v1/${deviceToken}/telemetry`; const payload = { method: 'post', url, data: JSON.stringify({ ts: ts || Date.now(), values: telemetry }), headers: { 'Content-type': 'application/json', Accept: 'application/json', }, }; try { const response = await axios(payload); if (response.status === 200) { return { success: true }; } } catch (err) { return { error: true, message: `pushAttributes(), Push telemetry by token error: ${err}` }; } } let entityId = objectId; if (entityId === null || typeof entityId === 'undefined') { entityId = await get.objectID(name, entityType); if (entityId.error) { return { error: true, message: `Error while getting entity id using name ${name}. Error: ${entityId.message}` }; } } let attributesStatus = false if ((typeof attributes !== 'undefined') && (attributes !== null)) { const url = `http://${process.env.TB_HOST}:${process.env.TB_PORT}/api/plugins/telemetry/${entityType.toUpperCase()}/${entityId}/attributes/SERVER_SCOPE`; try { await axios(url, { method: 'post', data: JSON.stringify(attributes), headers: { 'Content-Type': 'application/json', 'X-Authorization': `Bearer ${process.env[tokenRand+'TB_TOKEN']}`, }, }); attributesStatus = true } catch (err) { return { error: true, message: `Push attributes failed! Error: ${err}` }; } }else attributesStatus = true let telemetryStatus = false if ((telemetry !== null || typeof telemetry !== 'undefined')) { let url = ''; let payload = {}; switch (entityType.toUpperCase()) { case possibleEntityTypes.asset: { url = `http://${process.env.TB_HOST}:${process.env.TB_PORT}/api/plugins/telemetry/${entityType.toUpperCase()}/${entityId}/timeseries/SERVER_SCOPE`; payload = { method: 'post', url, data: JSON.stringify({ ts: ts || Date.now(), values: telemetry }), headers: { 'Content-type': 'application/json', 'X-Authorization': `Bearer ${process.env[tokenRand+'TB_TOKEN']}`, }, }; break; } case possibleEntityTypes.device: { const token = await get.getDeviceToken(entityId); // If error happened, getDeviceToken() return .error if (token.error) { return { error: true, message: deviceToken.message }; } url = `http://${process.env.TB_HOST}:${process.env.TB_PORT}/api/v1/${token}/telemetry`; payload = { method: 'post', url, data: JSON.stringify({ ts: ts || Date.now(), values: telemetry }), headers: { 'Content-type': 'application/json', Accept: 'application/json', }, }; break; } default: return { error: true, message: `Get unknown TB type ${entityType} !` }; } try { const response = await axios(payload); if (response.status === 200) { telemetryStatus = true } } catch (err) { return { error: true, message: `pushAttributes(), Error: ${err}` }; } } else telemetryStatus = true if(telemetryStatus && attributesStatus) return {result: true} } async function pushAlarm(entityName, entityType, alarmDetails, alarmType, ts, tenantId, entityId = null) { if ((typeof entityName === 'undefined' || entityName === null) || (typeof entityType === 'undefined' || entityType === null)) { return { error: true, message: 'Error: entityName or entityType are not defined or null!' }; } if (entityId === null) { entityId = await get.objectID(entityName, entityType); } const logAttrs = { entityId: { entityType: entityType.toUpperCase(), id: { id: new Date().getTime(), }, }, originator: { entityType: entityType.toUpperCase(), id: entityId, }, tenantId: { entityType: 'TENANT', id: tenantId, }, severity: 'MINOR', type: `${alarmType} hide: ${new Date().getTime()}`, ackTime: `hide: ${new Date(ts).getTime()}`, status: 'ACTIVE_UNACK', createdTime: new Date(ts).getTime(), details: alarmDetails, }; const urlLog = `http://${process.env.TB_HOST}:${process.env.TB_PORT}/api/alarm`; try { let ans = await fetch(urlLog, { method: 'post', body: JSON.stringify(logAttrs), headers: { 'Content-Type': 'application/json', 'X-Authorization': `Bearer ${process.env[tokenRand+'TB_TOKEN']}`, }, }); ans = await ans.json(); return { entityId: ans.originator.id, alarmId: ans.id.id, }; } catch (err) { return { error: true, message: `pushAlarm(), Error: ${err}` }; } } module.exports = { createRelation, pushAttributes, createEntityView, createEntity, pushAlarm, };