foobot-graphql
Version:
GraphQL server for Foobot device data.
149 lines (129 loc) • 4.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
exports.bucketize = bucketize;
exports.average = average;
exports.averageBucket = averageBucket;
exports.toAveragedData = toAveragedData;
var _decimal = require('decimal.js');
var _decimal2 = _interopRequireDefault(_decimal);
var _client = require('./client');
var _client2 = _interopRequireDefault(_client);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Instead of requesting averaged data from the API, which uses up our request
* limit, we can instead always request the highest-resolution data and perform
* the averaging ourselves. Not only will this help stay under the request
* limit, but it will also be faster since we don't need to fetch data we
* already have. This module implements helpers for averaging data as reasonably
* close to the real API as possible, so that results are indistinguishable
* from the real thing.
*
* Run this file as a standalone script to compare our results with live API
* results.
*/
var debug = require('debug')('foobot-graphql:average-by');
/**
* Given an array of datapoints, group them into buckets using `averageBy` to
* determine the bucket size.
*/
function bucketize(datapoints, period, averageBy) {
datapoints = datapoints.slice();
averageBy = averageBy || 300;
var bucket = [];
var buckets = [bucket];
var lastTime = datapoints[datapoints.length - 1][0];
var cutoff = lastTime - period + averageBy;
while (datapoints.length) {
var datapoint = datapoints[0];
if (datapoint[0] < cutoff) {
datapoints.shift();
bucket.push([cutoff - averageBy].concat((0, _toConsumableArray3.default)(datapoint.slice(1))));
} else {
cutoff += averageBy;
bucket = [];
buckets.push(bucket);
}
}
var beforeLength = buckets.length;
buckets = buckets.filter(function (bucket) {
return bucket.length !== 0;
});
var afterLength = buckets.length;
var removed = beforeLength - afterLength;
debug('Bucketizing resulted in ' + afterLength + ' bucket(s) (' + removed + ' removed).');
return buckets;
}
/**
* Return the average of the `data` array, calculated using the arbitrary
* precision Decimal type to avoid summation errors.
*/
function average(data) {
if (data.length) {
var sum = data.reduce(function (sum, x) {
return sum.plus(x);
}, new _decimal2.default(0));
var avg = sum.dividedBy(data.length);
return parseFloat(avg.toPrecision(9));
}
return 0;
}
function averageBucket(datapoints) {
var first = datapoints[0];
if (first) {
return first.map(function (value, i) {
return i === 0 ? value : average(datapoints.map(function (datapoint) {
return datapoint[i];
}));
});
}
return [];
}
function toAveragedData(data, period, averageBy) {
debug('Averaging dataset. period=' + period + ' averageBy=' + averageBy);
var buckets = bucketize(data.datapoints, period, averageBy);
var datapoints = buckets.map(averageBucket);
var first = datapoints[0];
var last = datapoints[datapoints.length - 1];
return (0, _extends3.default)({}, data, {
start: first ? first[0] : null,
end: last ? last[0] : null,
datapoints: datapoints
});
}
if (require.main === module) {
(function () {
require('dotenv').config();
var _require = require('./util'),
logObject = _require.logObject,
logError = _require.logError,
safeExit = _require.safeExit;
var client = new _client2.default();
var uuid = process.argv[2];
var period = parseInt(process.argv[3] || 0, 10);
var averageBy = parseInt(process.argv[4] || 300, 10);
client.datapoints(uuid, { period: period, averageBy: averageBy }).then(function (data) {
console.log('API result:');
logObject(data.datapoints.map(function (datapoint) {
return [new Date(datapoint[0] * 1000)].concat(datapoint.slice(1));
}));
return client.datapoints(uuid, { period: period, averageBy: 0 });
}).then(function (data) {
console.log('Local result:');
if (averageBy >= 300) {
data = toAveragedData(data, period, averageBy);
}
logObject(data.datapoints.map(function (datapoint) {
return [new Date(datapoint[0] * 1000)].concat(datapoint.slice(1));
}));
}).catch(function (err) {
logError(err);
safeExit(1);
});
})();
}