foobot-graphql
Version:
GraphQL server for Foobot device data.
172 lines (149 loc) • 5.54 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _averageBy = require('./average-by');
var _util = require('./util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* A class for storing data returned by the Foobot API. Since the API is rate
* limited, we want to avoid fetching data that we've already seen. Use this
* class to store the highest resolution, un-averaged data returned by
* the API. Consumers can then request the data from this cache instead, and
* it'll do the necessary slicing and averaging using `period` and `averageBy`.
*/
var debug = require('debug')('foobot-graphql:data-cache');
var MAX_CONNECTED_DISTANCE = 6 * _util.ONE_MINUTE;
var MAX_HISTORY_SIZE = 210384; // 2 years worth of five-minute intervals
var DataCache = function () {
function DataCache() {
(0, _classCallCheck3.default)(this, DataCache);
this.devices = {};
}
(0, _createClass3.default)(DataCache, [{
key: 'updateData',
value: function updateData(uuid, data) {
var device = this.devices[uuid] = this.devices[uuid] || {};
device.uuid = uuid;
device.sensors = data.sensors;
device.units = data.units;
device.datapoints = device.datapoints || [];
var j = 0;
var prepended = 0;
var appended = 0;
var inserted = 0;
var skipped = 0;
var pruned = 0;
for (var i = 0; i < data.datapoints.length; i++) {
var datapoint = data.datapoints[i];
var handled = false;
while (!handled) {
if (j >= device.datapoints.length) {
handled = true;
device.datapoints.push(datapoint);
device.date = data.date;
device.expires = data.expires;
appended += 1;
} else if (datapoint[0] < device.datapoints[j][0]) {
handled = true;
device.datapoints.splice(j, 0, datapoint);
if (j) {
inserted += 1;
} else {
prepended += 1;
}
j += 1;
} else if (datapoint[0] === device.datapoints[j][0]) {
handled = true;
skipped += 1;
j += 1;
} else if (datapoint[0] > device.datapoints[j][0]) {
j += 1;
}
}
}
if (device.datapoints.length > MAX_HISTORY_SIZE) {
pruned = device.datapoints.length - MAX_HISTORY_SIZE;
device.datapoints.splice(0, pruned);
}
debug('Added datapoints. ' + ('prepended=' + prepended + ' ') + ('inserted=' + inserted + ' ') + ('appended=' + appended + ' ') + ('skipped=' + skipped + ' ') + ('pruned=' + pruned));
}
}, {
key: 'add',
value: function add(uuid, data) {
this.updateData(uuid, data);
}
}, {
key: 'hasCompleteData',
value: function hasCompleteData(uuid, period) {
var device = this.devices[uuid] || { datapoints: [] };
var datapoints = device.datapoints;
if (datapoints.length) {
var _ret = function () {
var last = datapoints[datapoints.length - 1];
var cutoff = last[0] - period;
var index = datapoints.findIndex(function (datapoint) {
return datapoint[0] >= cutoff;
});
if (index === -1) {
return {
v: false
};
}
return {
v: datapoints.slice(index).every(function (datapoint, i, array) {
var time = datapoint[0] * 1000;
var prevTime = (i === 0 ? cutoff : array[i - 1][0]) * 1000;
return time - prevTime <= MAX_CONNECTED_DISTANCE;
})
};
}();
if ((typeof _ret === 'undefined' ? 'undefined' : (0, _typeof3.default)(_ret)) === "object") return _ret.v;
}
return false;
}
}, {
key: 'get',
value: function get(uuid, period) {
var averageBy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var device = this.devices[uuid] || {
uuid: uuid,
start: null,
end: null,
sensors: ['time', 'pm', 'tmp', 'hum', 'co2', 'voc', 'allpollu'],
units: ['s', 'ugm3', 'C', 'pc', 'ppm', 'ppb', '%'],
datapoints: []
};
var _device = device,
datapoints = _device.datapoints;
if (datapoints.length) {
(function () {
var last = datapoints[datapoints.length - 1];
var cutoff = last[0] - period;
var index = datapoints.findIndex(function (datapoint) {
return datapoint[0] >= cutoff;
});
device = (0, _extends3.default)({}, device, {
start: datapoints[index][0],
end: last[0],
datapoints: datapoints.slice(index)
});
if (averageBy >= 300) {
device = (0, _averageBy.toAveragedData)(device, period, averageBy);
}
})();
}
return device;
}
}]);
return DataCache;
}();
exports.default = DataCache;