2017-05-24 10:39:33 +03:00
|
|
|
/*
|
2019-02-01 16:39:33 +02:00
|
|
|
* Copyright © 2016-2019 The Thingsboard Authors
|
2017-05-24 10:39:33 +03:00
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
export default angular.module('thingsboard.api.attribute', [])
|
|
|
|
|
.factory('attributeService', AttributeService)
|
|
|
|
|
.name;
|
|
|
|
|
|
|
|
|
|
/*@ngInject*/
|
|
|
|
|
function AttributeService($http, $q, $filter, types, telemetryWebsocketService) {
|
|
|
|
|
|
|
|
|
|
var entityAttributesSubscriptionMap = {};
|
|
|
|
|
|
|
|
|
|
var service = {
|
|
|
|
|
getEntityKeys: getEntityKeys,
|
|
|
|
|
getEntityTimeseriesValues: getEntityTimeseriesValues,
|
|
|
|
|
getEntityAttributesValues: getEntityAttributesValues,
|
|
|
|
|
getEntityAttributes: getEntityAttributes,
|
|
|
|
|
subscribeForEntityAttributes: subscribeForEntityAttributes,
|
|
|
|
|
unsubscribeForEntityAttributes: unsubscribeForEntityAttributes,
|
|
|
|
|
saveEntityAttributes: saveEntityAttributes,
|
2019-05-20 11:57:43 +03:00
|
|
|
deleteEntityAttributes: deleteEntityAttributes,
|
|
|
|
|
saveEntityTimeseries: saveEntityTimeseries,
|
|
|
|
|
deleteEntityTimeseries: deleteEntityTimeseries
|
2017-05-24 10:39:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return service;
|
|
|
|
|
|
2017-12-29 19:09:34 +02:00
|
|
|
function getEntityKeys(entityType, entityId, query, type, config) {
|
2017-05-24 10:39:33 +03:00
|
|
|
var deferred = $q.defer();
|
|
|
|
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/';
|
|
|
|
|
if (type === types.dataKeyType.timeseries) {
|
|
|
|
|
url += 'timeseries';
|
|
|
|
|
} else if (type === types.dataKeyType.attribute) {
|
|
|
|
|
url += 'attributes';
|
|
|
|
|
}
|
2017-12-29 19:09:34 +02:00
|
|
|
$http.get(url, config).then(function success(response) {
|
2017-05-24 10:39:33 +03:00
|
|
|
var result = [];
|
|
|
|
|
if (response.data) {
|
|
|
|
|
if (query) {
|
|
|
|
|
var dataKeys = response.data;
|
|
|
|
|
var lowercaseQuery = angular.lowercase(query);
|
|
|
|
|
for (var i=0; i<dataKeys.length;i++) {
|
|
|
|
|
if (angular.lowercase(dataKeys[i]).indexOf(lowercaseQuery) === 0) {
|
|
|
|
|
result.push(dataKeys[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result = response.data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
deferred.resolve(result);
|
|
|
|
|
}, function fail(response) {
|
|
|
|
|
deferred.reject(response.data);
|
|
|
|
|
});
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getEntityTimeseriesValues(entityType, entityId, keys, startTs, endTs, limit) {
|
|
|
|
|
var deferred = $q.defer();
|
|
|
|
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/values/timeseries';
|
|
|
|
|
url += '?keys=' + keys;
|
|
|
|
|
url += '&startTs=' + startTs;
|
|
|
|
|
url += '&endTs=' + endTs;
|
|
|
|
|
if (angular.isDefined(limit)) {
|
|
|
|
|
url += '&limit=' + limit;
|
|
|
|
|
}
|
|
|
|
|
$http.get(url, null).then(function success(response) {
|
|
|
|
|
deferred.resolve(response.data);
|
|
|
|
|
}, function fail(response) {
|
|
|
|
|
deferred.reject(response.data);
|
|
|
|
|
});
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getEntityAttributesValues(entityType, entityId, attributeScope, keys, config) {
|
|
|
|
|
var deferred = $q.defer();
|
|
|
|
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/values/attributes/' + attributeScope;
|
|
|
|
|
if (keys && keys.length) {
|
|
|
|
|
url += '?keys=' + keys;
|
|
|
|
|
}
|
|
|
|
|
$http.get(url, config).then(function success(response) {
|
|
|
|
|
deferred.resolve(response.data);
|
|
|
|
|
}, function fail() {
|
|
|
|
|
deferred.reject();
|
|
|
|
|
});
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processAttributes(attributes, query, deferred, successCallback, update, apply) {
|
|
|
|
|
attributes = $filter('orderBy')(attributes, query.order);
|
|
|
|
|
if (query.search != null) {
|
|
|
|
|
attributes = $filter('filter')(attributes, {key: query.search});
|
|
|
|
|
}
|
|
|
|
|
var responseData = {
|
|
|
|
|
count: attributes.length
|
|
|
|
|
}
|
|
|
|
|
var startIndex = query.limit * (query.page - 1);
|
|
|
|
|
responseData.data = attributes.slice(startIndex, startIndex + query.limit);
|
|
|
|
|
successCallback(responseData, update, apply);
|
|
|
|
|
if (deferred) {
|
|
|
|
|
deferred.resolve();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getEntityAttributes(entityType, entityId, attributeScope, query, successCallback, config) {
|
|
|
|
|
var deferred = $q.defer();
|
|
|
|
|
var subscriptionId = entityType + entityId + attributeScope;
|
|
|
|
|
var eas = entityAttributesSubscriptionMap[subscriptionId];
|
|
|
|
|
if (eas) {
|
|
|
|
|
if (eas.attributes) {
|
|
|
|
|
processAttributes(eas.attributes, query, deferred, successCallback);
|
|
|
|
|
eas.subscriptionCallback = function(attributes) {
|
|
|
|
|
processAttributes(attributes, query, null, successCallback, true, true);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
eas.subscriptionCallback = function(attributes) {
|
|
|
|
|
processAttributes(attributes, query, deferred, successCallback, false, true);
|
|
|
|
|
eas.subscriptionCallback = function(attributes) {
|
|
|
|
|
processAttributes(attributes, query, null, successCallback, true, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/values/attributes/' + attributeScope;
|
|
|
|
|
$http.get(url, config).then(function success(response) {
|
|
|
|
|
processAttributes(response.data, query, deferred, successCallback);
|
|
|
|
|
}, function fail() {
|
|
|
|
|
deferred.reject();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return deferred;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onSubscriptionData(data, subscriptionId) {
|
|
|
|
|
var entityAttributesSubscription = entityAttributesSubscriptionMap[subscriptionId];
|
|
|
|
|
if (entityAttributesSubscription) {
|
|
|
|
|
if (!entityAttributesSubscription.attributes) {
|
|
|
|
|
entityAttributesSubscription.attributes = [];
|
|
|
|
|
entityAttributesSubscription.keys = {};
|
|
|
|
|
}
|
|
|
|
|
var attributes = entityAttributesSubscription.attributes;
|
|
|
|
|
var keys = entityAttributesSubscription.keys;
|
|
|
|
|
for (var key in data) {
|
|
|
|
|
var index = keys[key];
|
|
|
|
|
var attribute;
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
attribute = attributes[index];
|
|
|
|
|
} else {
|
|
|
|
|
attribute = {
|
|
|
|
|
key: key
|
|
|
|
|
};
|
|
|
|
|
index = attributes.push(attribute)-1;
|
|
|
|
|
keys[key] = index;
|
|
|
|
|
}
|
|
|
|
|
var attrData = data[key][0];
|
|
|
|
|
attribute.lastUpdateTs = attrData[0];
|
|
|
|
|
attribute.value = attrData[1];
|
|
|
|
|
}
|
|
|
|
|
if (entityAttributesSubscription.subscriptionCallback) {
|
|
|
|
|
entityAttributesSubscription.subscriptionCallback(attributes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function subscribeForEntityAttributes(entityType, entityId, attributeScope) {
|
|
|
|
|
var subscriptionId = entityType + entityId + attributeScope;
|
|
|
|
|
var entityAttributesSubscription = entityAttributesSubscriptionMap[subscriptionId];
|
|
|
|
|
if (!entityAttributesSubscription) {
|
|
|
|
|
var subscriptionCommand = {
|
|
|
|
|
entityType: entityType,
|
|
|
|
|
entityId: entityId,
|
|
|
|
|
scope: attributeScope
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var type = attributeScope === types.latestTelemetry.value ?
|
|
|
|
|
types.dataKeyType.timeseries : types.dataKeyType.attribute;
|
|
|
|
|
|
|
|
|
|
var subscriber = {
|
2017-09-09 14:37:44 +03:00
|
|
|
subscriptionCommands: [subscriptionCommand],
|
2017-05-24 10:39:33 +03:00
|
|
|
type: type,
|
|
|
|
|
onData: function (data) {
|
|
|
|
|
if (data.data) {
|
|
|
|
|
onSubscriptionData(data.data, subscriptionId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
entityAttributesSubscription = {
|
|
|
|
|
subscriber: subscriber,
|
|
|
|
|
attributes: null
|
|
|
|
|
};
|
|
|
|
|
entityAttributesSubscriptionMap[subscriptionId] = entityAttributesSubscription;
|
|
|
|
|
telemetryWebsocketService.subscribe(subscriber);
|
|
|
|
|
}
|
|
|
|
|
return subscriptionId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function unsubscribeForEntityAttributes(subscriptionId) {
|
|
|
|
|
var entityAttributesSubscription = entityAttributesSubscriptionMap[subscriptionId];
|
|
|
|
|
if (entityAttributesSubscription) {
|
|
|
|
|
telemetryWebsocketService.unsubscribe(entityAttributesSubscription.subscriber);
|
|
|
|
|
delete entityAttributesSubscriptionMap[subscriptionId];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-20 11:57:43 +03:00
|
|
|
function saveEntityAttributes(entityType, entityId, attributeScope, attributes, config) {
|
|
|
|
|
config = config || {};
|
2017-05-24 10:39:33 +03:00
|
|
|
var deferred = $q.defer();
|
|
|
|
|
var attributesData = {};
|
|
|
|
|
var deleteAttributes = [];
|
|
|
|
|
for (var a=0; a<attributes.length;a++) {
|
|
|
|
|
if (angular.isDefined(attributes[a].value) && attributes[a].value !== null) {
|
|
|
|
|
attributesData[attributes[a].key] = attributes[a].value;
|
|
|
|
|
} else {
|
|
|
|
|
deleteAttributes.push(attributes[a]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
var deleteEntityAttributesPromise;
|
|
|
|
|
if (deleteAttributes.length) {
|
|
|
|
|
deleteEntityAttributesPromise = deleteEntityAttributes(entityType, entityId, attributeScope, deleteAttributes);
|
|
|
|
|
}
|
|
|
|
|
if (Object.keys(attributesData).length) {
|
|
|
|
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope;
|
2019-05-20 11:57:43 +03:00
|
|
|
$http.post(url, attributesData, config).then(function success(response) {
|
2017-05-24 10:39:33 +03:00
|
|
|
if (deleteEntityAttributesPromise) {
|
|
|
|
|
deleteEntityAttributesPromise.then(
|
|
|
|
|
function success() {
|
|
|
|
|
deferred.resolve(response.data);
|
|
|
|
|
},
|
2019-05-23 17:56:22 +03:00
|
|
|
function fail() {
|
|
|
|
|
deferred.reject();
|
2017-05-24 10:39:33 +03:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
deferred.resolve(response.data);
|
|
|
|
|
}
|
2019-05-23 17:56:22 +03:00
|
|
|
}, function fail() {
|
|
|
|
|
deferred.reject();
|
2017-05-24 10:39:33 +03:00
|
|
|
});
|
|
|
|
|
} else if (deleteEntityAttributesPromise) {
|
|
|
|
|
deleteEntityAttributesPromise.then(
|
|
|
|
|
function success() {
|
|
|
|
|
deferred.resolve();
|
|
|
|
|
},
|
2019-05-23 17:56:22 +03:00
|
|
|
function fail() {
|
|
|
|
|
deferred.reject();
|
2017-05-24 10:39:33 +03:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
deferred.resolve();
|
|
|
|
|
}
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-20 11:57:43 +03:00
|
|
|
function saveEntityTimeseries(entityType, entityId, timeseriesScope, timeseries, config) {
|
|
|
|
|
config = config || {};
|
|
|
|
|
var deferred = $q.defer();
|
|
|
|
|
var timeseriesData = {};
|
|
|
|
|
var deleteTimeseries = [];
|
|
|
|
|
for (var a=0; a<timeseries.length;a++) {
|
|
|
|
|
if (angular.isDefined(timeseries[a].value) && timeseries[a].value !== null) {
|
|
|
|
|
timeseriesData[timeseries[a].key] = timeseries[a].value;
|
|
|
|
|
} else {
|
|
|
|
|
deleteTimeseries.push(timeseries[a]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
var deleteEntityTimeseriesPromise;
|
|
|
|
|
if (deleteTimeseries.length) {
|
2019-05-21 19:00:52 +03:00
|
|
|
deleteEntityTimeseriesPromise = deleteEntityTimeseries(entityType, entityId, deleteTimeseries, config);
|
2019-05-20 11:57:43 +03:00
|
|
|
}
|
|
|
|
|
if (Object.keys(timeseriesData).length) {
|
|
|
|
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/' + timeseriesScope;
|
|
|
|
|
$http.post(url, timeseriesData, config).then(function success(response) {
|
|
|
|
|
if (deleteEntityTimeseriesPromise) {
|
|
|
|
|
deleteEntityTimeseriesPromise.then(
|
|
|
|
|
function success() {
|
|
|
|
|
deferred.resolve(response.data);
|
|
|
|
|
},
|
2019-05-23 17:56:22 +03:00
|
|
|
function fail() {
|
|
|
|
|
deferred.reject();
|
2019-05-20 11:57:43 +03:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
deferred.resolve(response.data);
|
|
|
|
|
}
|
2019-05-23 17:56:22 +03:00
|
|
|
}, function fail() {
|
|
|
|
|
deferred.reject();
|
2019-05-20 11:57:43 +03:00
|
|
|
});
|
|
|
|
|
} else if (deleteEntityTimeseriesPromise) {
|
|
|
|
|
deleteEntityTimeseriesPromise.then(
|
|
|
|
|
function success() {
|
|
|
|
|
deferred.resolve();
|
|
|
|
|
},
|
2019-05-23 17:56:22 +03:00
|
|
|
function fail() {
|
|
|
|
|
deferred.reject();
|
2019-05-20 11:57:43 +03:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
deferred.resolve();
|
|
|
|
|
}
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 19:00:52 +03:00
|
|
|
function deleteEntityAttributes(entityType, entityId, attributeScope, attributes, config) {
|
|
|
|
|
config = config || {};
|
2017-05-24 10:39:33 +03:00
|
|
|
var deferred = $q.defer();
|
|
|
|
|
var keys = '';
|
|
|
|
|
for (var i = 0; i < attributes.length; i++) {
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
keys += ',';
|
|
|
|
|
}
|
|
|
|
|
keys += attributes[i].key;
|
|
|
|
|
}
|
|
|
|
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope + '?keys=' + keys;
|
2019-05-21 19:00:52 +03:00
|
|
|
$http.delete(url, config).then(function success() {
|
2017-05-24 10:39:33 +03:00
|
|
|
deferred.resolve();
|
2019-05-23 17:56:22 +03:00
|
|
|
}, function fail() {
|
|
|
|
|
deferred.reject();
|
2017-05-24 10:39:33 +03:00
|
|
|
});
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 19:00:52 +03:00
|
|
|
function deleteEntityTimeseries(entityType, entityId, timeseries, config) {
|
|
|
|
|
config = config || {};
|
2019-05-20 11:57:43 +03:00
|
|
|
var deferred = $q.defer();
|
|
|
|
|
var keys = '';
|
|
|
|
|
for (var i = 0; i < timeseries.length; i++) {
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
keys += ',';
|
|
|
|
|
}
|
|
|
|
|
keys += timeseries[i].key;
|
|
|
|
|
}
|
|
|
|
|
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/delete' + '?keys=' + keys;
|
2019-05-21 19:00:52 +03:00
|
|
|
$http.delete(url, config).then(function success() {
|
2019-05-20 11:57:43 +03:00
|
|
|
deferred.resolve();
|
2019-05-23 17:56:22 +03:00
|
|
|
}, function fail() {
|
|
|
|
|
deferred.reject();
|
2019-05-20 11:57:43 +03:00
|
|
|
});
|
|
|
|
|
return deferred.promise;
|
|
|
|
|
}
|
2017-05-24 10:39:33 +03:00
|
|
|
|
|
|
|
|
}
|