/*
* Copyright © 2016 The Thingsboard Authors
*
* 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.
*/
import thingsboardTypes from '../common/types.constant';
export default angular.module('thingsboard.api.device', [thingsboardTypes])
.factory('deviceService', DeviceService)
.name;
/*@ngInject*/
function DeviceService($http, $q, $filter, telemetryWebsocketService, types) {
var deviceAttributesSubscriptionMap = {};
var service = {
assignDeviceToCustomer: assignDeviceToCustomer,
deleteDevice: deleteDevice,
getCustomerDevices: getCustomerDevices,
getDevice: getDevice,
getDeviceCredentials: getDeviceCredentials,
getDeviceKeys: getDeviceKeys,
getDeviceTimeseriesValues: getDeviceTimeseriesValues,
getTenantDevices: getTenantDevices,
saveDevice: saveDevice,
saveDeviceCredentials: saveDeviceCredentials,
unassignDeviceFromCustomer: unassignDeviceFromCustomer,
getDeviceAttributes: getDeviceAttributes,
subscribeForDeviceAttributes: subscribeForDeviceAttributes,
unsubscribeForDeviceAttributes: unsubscribeForDeviceAttributes,
saveDeviceAttributes: saveDeviceAttributes,
deleteDeviceAttributes: deleteDeviceAttributes,
sendOneWayRpcCommand: sendOneWayRpcCommand,
sendTwoWayRpcCommand: sendTwoWayRpcCommand
}
return service;
function getTenantDevices(pageLink) {
var deferred = $q.defer();
var url = '/api/tenant/devices?limit=' + pageLink.limit;
if (angular.isDefined(pageLink.textSearch)) {
url += '&textSearch=' + pageLink.textSearch;
}
if (angular.isDefined(pageLink.idOffset)) {
url += '&idOffset=' + pageLink.idOffset;
}
if (angular.isDefined(pageLink.textOffset)) {
url += '&textOffset=' + pageLink.textOffset;
}
$http.get(url, null).then(function success(response) {
deferred.resolve(response.data);
}, function fail() {
deferred.reject();
});
return deferred.promise;
}
function getCustomerDevices(customerId, pageLink) {
var deferred = $q.defer();
var url = '/api/customer/' + customerId + '/devices?limit=' + pageLink.limit;
if (angular.isDefined(pageLink.textSearch)) {
url += '&textSearch=' + pageLink.textSearch;
}
if (angular.isDefined(pageLink.idOffset)) {
url += '&idOffset=' + pageLink.idOffset;
}
if (angular.isDefined(pageLink.textOffset)) {
url += '&textOffset=' + pageLink.textOffset;
}
$http.get(url, null).then(function success(response) {
deferred.resolve(response.data);
}, function fail() {
deferred.reject();
});
return deferred.promise;
}
function getDevice(deviceId) {
var deferred = $q.defer();
var url = '/api/device/' + deviceId;
$http.get(url, null).then(function success(response) {
deferred.resolve(response.data);
}, function fail(response) {
deferred.reject(response.data);
});
return deferred.promise;
}
function saveDevice(device) {
var deferred = $q.defer();
var url = '/api/device';
$http.post(url, device).then(function success(response) {
deferred.resolve(response.data);
}, function fail(response) {
deferred.reject(response.data);
});
return deferred.promise;
}
function deleteDevice(deviceId) {
var deferred = $q.defer();
var url = '/api/device/' + deviceId;
$http.delete(url).then(function success() {
deferred.resolve();
}, function fail(response) {
deferred.reject(response.data);
});
return deferred.promise;
}
function getDeviceCredentials(deviceId) {
var deferred = $q.defer();
var url = '/api/device/' + deviceId + '/credentials';
$http.get(url, null).then(function success(response) {
deferred.resolve(response.data);
}, function fail(response) {
deferred.reject(response.data);
});
return deferred.promise;
}
function saveDeviceCredentials(deviceCredentials) {
var deferred = $q.defer();
var url = '/api/device/credentials';
$http.post(url, deviceCredentials).then(function success(response) {
deferred.resolve(response.data);
}, function fail(response) {
deferred.reject(response.data);
});
return deferred.promise;
}
function assignDeviceToCustomer(customerId, deviceId) {
var deferred = $q.defer();
var url = '/api/customer/' + customerId + '/device/' + deviceId;
$http.post(url, null).then(function success() {
deferred.resolve();
}, function fail(response) {
deferred.reject(response.data);
});
return deferred.promise;
}
function unassignDeviceFromCustomer(deviceId) {
var deferred = $q.defer();
var url = '/api/customer/device/' + deviceId;
$http.delete(url).then(function success() {
deferred.resolve();
}, function fail(response) {
deferred.reject(response.data);
});
return deferred.promise;
}
function getDeviceKeys(deviceId, query, type) {
var deferred = $q.defer();
var url = '/api/plugins/telemetry/' + deviceId + '/keys/';
if (type === types.dataKeyType.timeseries) {
url += 'timeseries';
} else if (type === types.dataKeyType.attribute) {
url += 'attributes';
}
$http.get(url, null).then(function success(response) {
var result = [];
if (response.data) {
if (query) {
var dataKeys = response.data;
var lowercaseQuery = angular.lowercase(query);
for (var i in dataKeys) {
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 getDeviceTimeseriesValues(deviceId, keys, startTs, endTs, limit) {
var deferred = $q.defer();
var url = '/api/plugins/telemetry/' + deviceId + '/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 processDeviceAttributes(attributes, query, deferred, successCallback, update) {
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);
if (deferred) {
deferred.resolve();
}
}
function getDeviceAttributes(deviceId, attributeScope, query, successCallback) {
var deferred = $q.defer();
var subscriptionId = deviceId + attributeScope;
var das = deviceAttributesSubscriptionMap[subscriptionId];
if (das) {
if (das.attributes) {
processDeviceAttributes(das.attributes, query, deferred, successCallback);
das.subscriptionCallback = function(attributes) {
processDeviceAttributes(attributes, query, null, successCallback, true);
}
} else {
das.subscriptionCallback = function(attributes) {
processDeviceAttributes(attributes, query, deferred, successCallback);
das.subscriptionCallback = function(attributes) {
processDeviceAttributes(attributes, query, null, successCallback, true);
}
}
}
} else {
var url = '/api/plugins/telemetry/' + deviceId + '/values/attributes/' + attributeScope;
$http.get(url, null).then(function success(response) {
processDeviceAttributes(response.data, query, deferred, successCallback);
}, function fail() {
deferred.reject();
});
}
return deferred;
}
function onSubscriptionData(data, subscriptionId) {
var deviceAttributesSubscription = deviceAttributesSubscriptionMap[subscriptionId];
if (deviceAttributesSubscription) {
if (!deviceAttributesSubscription.attributes) {
deviceAttributesSubscription.attributes = [];
deviceAttributesSubscription.keys = {};
}
var attributes = deviceAttributesSubscription.attributes;
var keys = deviceAttributesSubscription.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 (deviceAttributesSubscription.subscriptionCallback) {
deviceAttributesSubscription.subscriptionCallback(attributes);
}
}
}
function subscribeForDeviceAttributes(deviceId, attributeScope) {
var subscriptionId = deviceId + attributeScope;
var deviceAttributesSubscription = deviceAttributesSubscriptionMap[subscriptionId];
if (!deviceAttributesSubscription) {
var subscriptionCommand = {
deviceId: deviceId
};
var type = attributeScope === types.latestTelemetry.value ?
types.dataKeyType.timeseries : types.dataKeyType.attribute;
var subscriber = {
subscriptionCommand: subscriptionCommand,
type: type,
onData: function (data) {
onSubscriptionData(data, subscriptionId);
}
};
telemetryWebsocketService.subscribe(subscriber);
deviceAttributesSubscription = {
subscriber: subscriber,
attributes: null
}
deviceAttributesSubscriptionMap[subscriptionId] = deviceAttributesSubscription;
}
return subscriptionId;
}
function unsubscribeForDeviceAttributes(subscriptionId) {
var deviceAttributesSubscription = deviceAttributesSubscriptionMap[subscriptionId];
if (deviceAttributesSubscription) {
telemetryWebsocketService.unsubscribe(deviceAttributesSubscription.subscriber);
delete deviceAttributesSubscriptionMap[subscriptionId];
}
}
function saveDeviceAttributes(deviceId, attributeScope, attributes) {
var deferred = $q.defer();
var attributesData = {};
for (var a in attributes) {
attributesData[attributes[a].key] = attributes[a].value;
}
var url = '/api/plugins/telemetry/' + deviceId + '/' + attributeScope;
$http.post(url, attributesData).then(function success(response) {
deferred.resolve(response.data);
}, function fail(response) {
deferred.reject(response.data);
});
return deferred.promise;
}
function deleteDeviceAttributes(deviceId, attributeScope, attributes) {
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/' + deviceId + '/' + attributeScope + '?keys=' + keys;
$http.delete(url).then(function success() {
deferred.resolve();
}, function fail() {
deferred.reject();
});
return deferred.promise;
}
function sendOneWayRpcCommand(deviceId, requestBody) {
var deferred = $q.defer();
var url = '/api/plugins/rpc/oneway/' + deviceId;
$http.post(url, requestBody).then(function success(response) {
deferred.resolve(response.data);
}, function fail(rejection) {
deferred.reject(rejection);
});
return deferred.promise;
}
function sendTwoWayRpcCommand(deviceId, requestBody) {
var deferred = $q.defer();
var url = '/api/plugins/rpc/twoway/' + deviceId;
$http.post(url, requestBody).then(function success(response) {
deferred.resolve(response.data);
}, function fail(rejection) {
deferred.reject(rejection);
});
return deferred.promise;
}
}