UNPKG

node-anemometer

Version:

Measuring the wind speed with an anemometer

249 lines (248 loc) 8.53 kB
"use strict"; 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 }; }