node-anemometer
Version:
Measuring the wind speed with an anemometer
249 lines (248 loc) • 8.53 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.WindSpeed = exports.WindSpeedUnits = void 0;
exports.sleep = sleep;
exports.round = round;
exports.calcFactor = calcFactor;
exports.bcdToByte = bcdToByte;
exports.byteToBCD = byteToBCD;
exports.scanBus = scanBus;
exports.runSave = runSave;
exports.getTotalPulses = getTotalPulses;
exports.getMaxIncreaseRate = getMaxIncreaseRate;
const i2c_bus_1 = require("i2c-bus");
var WindSpeedUnits;
(function (WindSpeedUnits) {
WindSpeedUnits["kilometersPerHour"] = "km/h";
WindSpeedUnits["metersPerSecond"] = "m/s";
WindSpeedUnits["knots"] = "kn";
})(WindSpeedUnits || (exports.WindSpeedUnits = WindSpeedUnits = {}));
/**
* Represents a WindSpeed unit with the specified value and unit type.
*/
class WindSpeed {
value;
unit;
/**
* Creates an instance of WindSpeed with a numeric value and unit type.
*
* @param value The numeric value of the WindSpeed.
* @param unit The unit type (e.g., km/h, m/s, kn).
*/
constructor(value, unit) {
this.value = value;
this.unit = unit;
}
/**
* Rounds the WindSpeed value to a specified number of decimal places.
*
* @param decimalPlaces The number of decimal places to round to.
* @returns The rounded WindSpeed value.
*/
rounded(decimalPlaces = 1) {
return round(this.value, decimalPlaces);
}
/**
* Converts the WindSpeed value to kilometers per hour (km/h).
*
* @returns A new WindSpeed instance with the value converted to km/h.
*/
toKilometersPerHour() {
switch (this.unit) {
case WindSpeedUnits.metersPerSecond:
return new WindSpeed(this.value * 3.6, WindSpeedUnits.kilometersPerHour);
case WindSpeedUnits.knots:
return new WindSpeed(this.value * 1.852, WindSpeedUnits.kilometersPerHour);
default:
return this;
}
}
/**
* Converts the WindSpeed value to meters per second (m/s).
*
* @returns A new WindSpeed instance with the value converted to m/s.
*/
toMetersPerSecond() {
switch (this.unit) {
case WindSpeedUnits.kilometersPerHour:
return new WindSpeed(this.value / 3.6, WindSpeedUnits.metersPerSecond);
case WindSpeedUnits.knots:
return new WindSpeed(this.value / 1.944, WindSpeedUnits.metersPerSecond);
default:
return this;
}
}
/**
* Converts the WindSpeed value to knots (kn).
*
* @returns A new WindSpeed instance with the value converted to knots.
*/
toKnots() {
switch (this.unit) {
case WindSpeedUnits.kilometersPerHour:
return new WindSpeed(this.value / 1.852, WindSpeedUnits.knots);
case WindSpeedUnits.metersPerSecond:
return new WindSpeed(this.value * 1.944, WindSpeedUnits.knots);
default:
return this;
}
}
}
exports.WindSpeed = WindSpeed;
/**
* Sleeps for a specified number of milliseconds.
* @param ms The number of milliseconds to sleep.
* @returns A promise that resolves after the specified time.
*/
async function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Rounds a number to a specified number of decimal places
* @param value The number to round
* @param decimalPlaces The number of decimal places
* @returns The rounded number
*/
function round(value, decimalPlaces) {
if (!isFinite(value) || decimalPlaces < 0) {
throw new Error('Invalid input for rounding!');
}
const factor = Math.pow(10, decimalPlaces);
return Math.round((value + Number.EPSILON) * factor) / factor;
}
/**
* Calculates the animeter factor based on radius and adjustment.
*
* __Calculation explained:__
* 1. Scope calculation (π * r * 2)
* 2. Convert centimeter to kilometer ( / 100000)
* 3. Convert to kilometers per hour ( * 3600)
* 4. Multiply adjustment
*
* @param radius Radius between midpoint and edge of a cup in centimeters.
* @param adjustment Power loss due to mechanics (approximately 1.18).
* @returns The calculated factor.
*/
function calcFactor(radius, adjustment) {
return ((Math.PI * radius * 2) / 100000) * 3600 * adjustment;
}
/**
* Converts a Binary-Coded Decimal (BCD) value to a byte.
*
* @param value The BCD value to convert.
* @returns The converted byte value.
*/
function bcdToByte(value) {
if (value >> 4 > 9 || (value & 0x0f) > 9) {
throw new Error(`Invalid value for byte convertion: ${value.toString(16)}`);
}
return (value >> 4) * 10 + (value & 0x0f);
}
/**
* Converts a byte value to Binary-Coded Decimal (BCD) format.
*
* @param value The byte value to convert.
* @returns The converted BCD value.
* @throws If the input value is invalid.
*/
function byteToBCD(value) {
if (value >= 100) {
throw new Error(`Invalid value for bcd convertion: ${value}`);
}
return (Math.floor(value / 10) << 4) | value % 10;
}
/**
* Returns an array of numbers, where each number represents the I2C address of a detected device.
* @see https://github.com/fivdi/i2c-bus#busscanstartaddr-endaddr-cb
*/
function scanBus(...args) {
const wire = (0, i2c_bus_1.openSync)(...args);
const result = wire.scanSync();
wire.closeSync();
return result;
}
/**
* Safely executes a promise and handles any errors, returning an optional fallback value if the promise fails.
*
* @template TResult The type of the value that the promise resolves to
* @template TFallback The type of the fallback value returned on failure
*
* @param promise The promise to execute
* @param returnOnFail The value to return if the promise rejects
* @param onCatch Optional callback to handle errors
*
* @returns A promise that resolves with either the result of the original promise or the fallback value
*/
async function runSave(promise, returnOnFail, onCatch) {
try {
return await promise;
}
catch (error) {
if (onCatch) {
try {
onCatch(error);
}
catch {
// Silently ignore errors in the error handler to prevent cascading failures
}
}
}
return returnOnFail;
}
/**
* Evaluates the total pulses and the duration based on the data records.
* This function calculates the total number of pulses (revolutions) considering possible sensor resets
* and the time span between the first and last record.
*
* @param data An array of data records containing the value and timestamp of each record.
* @returns An object with the total pulses and the duration in seconds.
*/
function getTotalPulses(data) {
if (data.length === 0) {
return { pulses: 0, timeSpan: 0 };
}
let pulses = 0;
let previousValue = data[0].value;
for (const record of data) {
if (record.value >= previousValue) {
pulses += record.value - previousValue;
}
else {
pulses += record.value;
}
previousValue = record.value;
}
const timeSpan = data[data.length - 1].timestamp - data[0].timestamp;
return { pulses, timeSpan };
}
/**
* Calculates the maximum rate of increase between consecutive data records.
* This function identifies the maximum rate of increase (pulses per second) between any two consecutive records,
* along with the step (number of pulses) and time span (in seconds) for that maximum rate.
*
* @param data An array of data records containing the value and timestamp of each record.
* @returns An object with the maximum rate of increase, the corresponding step, and time span.
*/
function getMaxIncreaseRate(data) {
if (data.length < 2) {
return { rate: 0, step: 0, timeSpan: 0 };
}
let maxRate = 0;
let maxStep = 0;
let maxTimeSpan = 0;
for (let i = 0; i < data.length - 1; i++) {
const startRecord = data[i];
const endRecord = data[i + 1];
const step = endRecord.value - startRecord.value;
const timeSpan = endRecord.timestamp - startRecord.timestamp;
if (timeSpan > 0) {
const rate = step / timeSpan;
if (rate > maxRate) {
maxRate = rate;
maxStep = step;
maxTimeSpan = timeSpan;
}
}
}
return { rate: maxRate, step: maxStep, timeSpan: maxTimeSpan };
}