diff --git a/README.md b/README.md index dec2baf..2ae0f99 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,37 @@ ![Node.js Package](https://github.com/oyve/signalk-barometer-trend/workflows/Node.js%20Package/badge.svg) # signalk-barometer-trend -Calculate the pressure trend of a barometer. Are there foul weather on the way? +Calculate pressure trend and get weather predictions from a barometer over time. Are there foul weather on the way? -## Install & Use -Note: To use this plugin you need at minimum a barometer connected to SignalK, i.e. the [bme680](https://www.google.com/search?client=firefox-b-d&q=bme680), outputting the SignalK-sentence `'environment.outside.pressure'`. +## Prerequisites +- A barometer, i.e. the [bme680](https://www.google.com/search?client=firefox-b-d&q=bme680), outputting `'environment.outside.pressure'` to SignalK +- Optional: GPS-coordinates to determinate if located in northern | southern hemisphere (default: northern) +- Optional: Temperature sensor and GPS-altitude for increased precision -Install the plugin through the SignalK plugin interface.\ -After installation you may want to 'Activate' it through the SignalK Plugin Config interface. +## Install & setup +Install the plugin through the SignalK plugin interface. 'Enable' it through the Plugin Config interface. -The plugin will output several new SignalK-values, such as: -``` -'environment.outside.pressure.trend.tendency' -'environment.outside.pressure.trend.severity' -'environment.outside.pressure.prediction.quadrant' -``` - -Based on the severity value it's possible to set an alarm, i.e. with the [Simple Notification](https://github.com/sbender9/signalk-simple-notifications)-plugin (see table below). - -If `'environment.outside.temperature'` and `'navigation.gnss.antennaAltitude'` (GPS altitude) is present, the plugin will make calculations by adjusting the pressure to sea level. Defaults are `altitude = 0` (sea level) and `temperature = 15C`.\ -(Note: The plugin will not change the pressure readings you observe in SignalK - just internally for calculations.) +![SignalK Plugin Config](/images/pluginConfig.png) -PS: It might take a couple of minutes before the plugin show any data, as it need to collect pressure readings to calculate a trend. The plugin is setup to read the pressure every 1 minute. Pressure readings older than three hours will be discarded. +- Sample Rate: More | fewer readings. This may result in a more | less "jumpy" barometer-trend. (Default = 60). +- Altitude Offset: Ajust for any differences between your sensor altitude to GPS-altitude. (Default = 0). -Note: If `'environment.outside.pressure.prediction.front.*` shows "N/A" - this means no front pressure pattern has been detected. It might take up to three hours to see anything, if at all. +## Use +It might take a couple of minutes before the plugin show any data, as it need to collect pressure readings to calculate a trend. The plugin will not change the pressure readings you observe in SignalK - only internally for calculations. -## More details +The plugin outputs several new SignalK-values, such as: -For more details please visit [github.com/oyve/barometer-trend](https://github.com/oyve/barometer-trend) library. +``` +'environment.outside.pressure.trend.tendency' +'environment.outside.pressure.trend.severity' +'environment.outside.pressure.prediction.pressureOnly' +... +``` ![SignalK Data Browser](/images/signalk_barometer_trend.png) -![SignalK Data Browser](/images/signalk_barometer_trend2.png) -## Possible severity values are (in parentheses) +## Alarms +Based on the severity value it's possible to set an alarm, using the [Simple Notification](https://github.com/sbender9/signalk-simple-notifications)-plugin (see severity table below). `'environment.outside.pressure.trend.severity'` @@ -44,10 +43,8 @@ FALLING: | RISING: (-3) FALLING.QUICKLY | (3) RISING.QUICKLY (-4) FALLING.RAPIDLY | (4) RISING.RAPIDLY -Based on the severity value you could set an alarm, i.e. with the [Simple Notification](https://github.com/sbender9/signalk-simple-notifications)-plugin. - ## Contribute -Please feel free to contribute to this plugin by creating a *Pull Request* including test code. +Please feel free to contribute to this plugin by creating an issue and/or a *Pull Request* including test code. ## Disclaimer - See all disclaimers by reading the README at the GitHub project ['barometer-trend'](https://github.com/oyve/barometer-trend), also by the same author, to understand the limitations of this plugin. @@ -56,8 +53,8 @@ Please feel free to contribute to this plugin by creating a *Pull Request* inclu * [GitHub: barometer-trend](https://github.com/oyve/barometer-trend) * [SignalK](http://signalk.org/) -## A real world example -This is actual data while developing the plugin. A tropical wave, OT-48, was moving through the Caribbean creating local heavy rainfall and stormy wind in Guadeloupe. +## Real world example +This is actual data while developing the plugin. A tropical wave, OT-48, was moving through the Caribbean creating local heavy rainfall and stormy winds in Guadeloupe. ![SigK Pressure Trend](/images/sigk_pressuretrend.jpg) @@ -65,4 +62,4 @@ This is actual data while developing the plugin. A tropical wave, OT-48, was mov NOAA Satelitte Photo The above GIF-animation is actual radar image from [Meteo France](http://www.meteo.fr/temps/domtom/antilles/pack-public/animation/anim_radar_mart_mf_com.html) at the time.\ -The above satelitte photo animation is from [NOAA](https://www.nhc.noaa.gov/satellite.php). +The above satelitte photo animation is from [NOAA](https://www.nhc.noaa.gov/satellite.php). \ No newline at end of file diff --git a/barometer.js b/barometer.js index e0285c3..3363649 100644 --- a/barometer.js +++ b/barometer.js @@ -1,60 +1,47 @@ 'use strict' const barometerTrend = require('barometer-trend'); +const map = require('./map'); +const lodash = require('lodash'); -const ENVIRONMENT_OUTSIDE_PRESSURE = 'environment.outside.pressure'; -const ENVIRONMENT_OUTSIDE_TEMPERATURE = 'environment.outside.temperature'; -const ENVIRONMENT_WIND_TWD = 'environment.wind.directionTrue'; -const NAVIGATION_POSITION = 'navigation.position'; -const NAVIGATION_ALTITUDE = 'navigation.gnss.antennaAltitude'; +const secondsToMilliseconds = (seconds) => seconds * 1000; +const DEFAULT_SAMPLE_RATE = secondsToMilliseconds(60); +const DEFAULT_ALTITUDE_CORRECTION = 0; -const ONE_MINUTE_MILLISECONDS = 60 * 1000; -const TEN_SECONDS_MILLISECONDS = 10 * 1000; +let sampleRate = DEFAULT_SAMPLE_RATE; //default +let altitudeCorrection = DEFAULT_ALTITUDE_CORRECTION; -const KELVIN = 273.15; - -const SUBSCRIPTIONS = [ - { path: ENVIRONMENT_WIND_TWD, period: TEN_SECONDS_MILLISECONDS, policy: "instant", minPeriod: ONE_MINUTE_MILLISECONDS }, - { path: NAVIGATION_POSITION, period: ONE_MINUTE_MILLISECONDS, policy: "instant", minPeriod: ONE_MINUTE_MILLISECONDS }, - { path: NAVIGATION_ALTITUDE, period: ONE_MINUTE_MILLISECONDS, policy: "instant", minPeriod: ONE_MINUTE_MILLISECONDS }, - { path: ENVIRONMENT_OUTSIDE_TEMPERATURE, period: ONE_MINUTE_MILLISECONDS, policy: "instant", minPeriod: ONE_MINUTE_MILLISECONDS }, - { path: ENVIRONMENT_OUTSIDE_PRESSURE, period: ONE_MINUTE_MILLISECONDS } -]; - -const pathPrefix = "environment.outside.pressure."; - -const OUTPUT_PATHS = { - "TREND_TENDENCY_COMBINED": pathPrefix + "trend", - "TREND_TENDENCY": pathPrefix + "trend.tendency", - "TREND_TREND": pathPrefix + "trend.trend", - "TREND_SEVERITY": pathPrefix + "trend.severity", - "TREND_DIFFERENCE_FROM": pathPrefix + "trend.from", - "TREND_DIFFERENCE_TO": pathPrefix + "trend.to", - "TREND_DIFFERENCE": pathPrefix + "trend.difference", - "TREND_DIFFERENCE_RATIO": pathPrefix + "trend.difference.ratio", - "TREND_DIFFERENCE_PERIOD": pathPrefix + "trend.difference.period", - - "PREDICTION_PRESSURE": pathPrefix + "prediction.pressureOnly", - "PREDICTION_QUADRANT": pathPrefix + "prediction.quadrant", - "PREDICTION_SEASON": pathPrefix + "prediction.season", - "PREDICTION_BEAUFORT_FORCE": pathPrefix + "prediction.beaufort", - "PREDICTION_BEAUFORT_DESCRIPTION": pathPrefix + "prediction.beaufort.description", - - "PREDICTION_FRONT_TENDENCY": pathPrefix + "prediction.front.tendency", - "PREDICTION_FRONT_PROGNOSE": pathPrefix + "prediction.front.prognose", - "PREDICTION_FRONT_WIND": pathPrefix + "prediction.front.wind", +/** + * + * @param {number} rate Pressure sample rate in milliseconds + */ +function setSampleRate(rate = DEFAULT_SAMPLE_RATE) { + if(!rate) return; + if (rate > 3600) rate = secondsToMilliseconds(3600); + if (rate < 60) rate = DEFAULT_SAMPLE_RATE; - "ASL": pathPrefix + "ASL", - "SYSTEM": pathPrefix + "system", + sampleRate = rate; + return rate; +} - "HISTORY_1HR": pathPrefix + "1hr", - "HISTORY_3HR": pathPrefix + "3hr", - "HISTORY_6HR": pathPrefix + "6hr", - "HISTORY_12HR": pathPrefix + "12hr", - "HISTORY_24HR": pathPrefix + "24hr", - "HISTORY_48HR": pathPrefix + "48hr" +/** + * + * @param {number} altitude Set Altitude correction in meters + * @returns + */ +function setAltitudeCorrection(altitude = DEFAULT_ALTITUDE_CORRECTION) { + if(altitude === null && altitude === undefined) return; + altitudeCorrection = altitude } -const latest = { +const SUBSCRIPTIONS = [ + { path: 'environment.wind.directionTrue', period: secondsToMilliseconds(30), policy: "instant", minPeriod: secondsToMilliseconds(60), handle: (value) => onTrueWindUpdated(value) }, + { path: 'navigation.position', period: secondsToMilliseconds(30), policy: "instant", minPeriod: secondsToMilliseconds(60), handle: (value) => onPositionUpdated(value) }, + { path: 'navigation.gnss.antennaAltitude', period: secondsToMilliseconds(30), policy: "instant", minPeriod: secondsToMilliseconds(60), handle: (value) => onAltitudeUpdated(value) }, + { path: 'environment.outside.temperature', period: secondsToMilliseconds(30), policy: "instant", minPeriod: secondsToMilliseconds(60), handle: (value) => onTemperatureUpdated(value) }, + { path: 'environment.outside.pressure', period: sampleRate, handle: (value) => onPressureUpdated(value) } +]; + +const TEMPLATE_LATEST = { twd: { time: null, value: null @@ -71,13 +58,8 @@ const latest = { } } -const pathHandles = [ - { path: ENVIRONMENT_OUTSIDE_PRESSURE, handle: (value) => onPressureUpdated(value) }, - { path: ENVIRONMENT_WIND_TWD, handle: (value) => onTrueWindUpdated(value) }, - { path: NAVIGATION_POSITION, handle: (value) => onPositionUpdated(value) }, - { path: NAVIGATION_ALTITUDE, handle: (value) => onAltitudeUpdated(value) }, - { path: ENVIRONMENT_OUTSIDE_TEMPERATURE, handle: (value) => onTemperatureUpdated(value) } -]; +let latest = null; +latest = lodash.cloneDeep(TEMPLATE_LATEST); /** * @@ -89,22 +71,25 @@ function onDeltasUpdate(deltas) { throw "Deltas cannot be null"; } - let deltaMessages = []; + let deltaValues = []; deltas.updates.forEach(u => { u.values.forEach((value) => { - let onDeltaUpdated = pathHandles.find((d) => d.path === value.path); + let onDeltaUpdated = SUBSCRIPTIONS.find((d) => d.path === value.path); if (onDeltaUpdated !== null) { let updates = onDeltaUpdated.handle(value.value); - if (updates !== null && updates !== undefined) { - updates.forEach((u) => deltaMessages.push(u)); + console.debug("Handle: " + JSON.stringify(value)); + + if (updates && updates.length > 0) { + //console.debug(JSON.stringify(updates)); + updates.forEach((update) => deltaValues.push(update)); } } }); }); - return deltaMessages; + return deltaValues; } function onPositionUpdated(value) { @@ -113,11 +98,11 @@ function onPositionUpdated(value) { } function onTemperatureUpdated(value) { - latest.temperature.value = toKelvinIfCelcius(value); + latest.temperature.value = value; } function onAltitudeUpdated(value) { - latest.altitude.value = value; + latest.altitude.value = value + altitudeCorrection; } function onTrueWindUpdated(value) { @@ -125,126 +110,43 @@ function onTrueWindUpdated(value) { latest.twd.value = value; } -/** - * - * @param {number} pressure Pressure - * @returns returns Pascal if pressure is recieved in hPa - */ -function toPaIfHpa(pressure) { - if (Math.trunc(pressure).toString().length <= 4) { - pressure *= 100; - } - - return pressure; -} - -/** - * - * @param {number} temperature Temperature - * @returns returns Kelvin if temperature is recieved in Celcius - */ -function toKelvinIfCelcius(temperature) { - if (Math.trunc(temperature).toString().length <= 2) { - temperature += KELVIN; - } - - return temperature; -} - /** * * @param {number} value Pressure value in (Pa) Pascal. * @returns {Array<[{path:path, value:value}]>} Delta JSON-array of updates */ function onPressureUpdated(value) { - if (value == null) throw new Error("Cannot add null value"); + if (!value) return; barometerTrend.addPressure( new Date(), - toPaIfHpa(value), + value, latest.altitude.value, latest.temperature.value, hasTWDWithinOneMinute() ? latest.twd.value : null); - let forecast = barometerTrend.getPredictions(isNortherHemisphere()); - - return forecast !== null ? prepareUpdate(forecast) : null; -} - -function prepareUpdate(forecast) { - const waitingMessage = "Waiting.."; - return [ - buildDeltaUpdate(OUTPUT_PATHS.TREND_TENDENCY_COMBINED, forecast !== null ? forecast.trend.tendency + "." + forecast.trend.trend : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.TREND_TENDENCY, forecast !== null ? forecast.trend.tendency : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.TREND_TREND, forecast !== null ? forecast.trend.trend : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.TREND_SEVERITY, forecast !== null ? forecast.trend.severity : waitingMessage), + let json = barometerTrend.getPredictions(isNorthernHemisphere()); - buildDeltaUpdate(OUTPUT_PATHS.TREND_DIFFERENCE_FROM, forecast !== null ? forecast.trend.from : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.TREND_DIFFERENCE_TO, forecast !== null ? forecast.trend.to : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.TREND_DIFFERENCE, forecast !== null ? forecast.trend.difference : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.TREND_DIFFERENCE_PERIOD, forecast !== null ? forecast.trend.period : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.TREND_DIFFERENCE_RATIO, forecast !== null ? forecast.trend.ratio : waitingMessage), - - buildDeltaUpdate(OUTPUT_PATHS.PREDICTION_PRESSURE, forecast !== null ? forecast.predictions.pressureOnly : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.PREDICTION_QUADRANT, forecast !== null ? forecast.predictions.quadrant : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.PREDICTION_SEASON, forecast !== null ? forecast.predictions.season : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.PREDICTION_BEAUFORT_FORCE, forecast !== null ? forecast.predictions.beaufort.force : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.PREDICTION_BEAUFORT_DESCRIPTION, forecast !== null ? forecast.predictions.beaufort.description : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.PREDICTION_FRONT_TENDENCY, forecast !== null ? forecast.predictions.front.tendency : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.PREDICTION_FRONT_PROGNOSE, forecast !== null ? forecast.predictions.front.prognose : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.PREDICTION_FRONT_WIND, forecast !== null ? forecast.predictions.front.wind : waitingMessage), - - buildDeltaUpdate(OUTPUT_PATHS.SYSTEM, forecast !== null ? forecast.system.name : null), - buildDeltaUpdate(OUTPUT_PATHS.ASL, forecast !== null ? forecast.lastPressure.value : null), - - buildDeltaUpdate(OUTPUT_PATHS.HISTORY_1HR, forecast !== null ? getHistory(forecast, 1) : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.HISTORY_3HR, forecast !== null ? getHistory(forecast, 3) : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.HISTORY_6HR, forecast !== null ? getHistory(forecast, 6) : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.HISTORY_12HR, forecast !== null ? getHistory(forecast, 12) : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.HISTORY_24HR, forecast !== null ? getHistory(forecast, 24) : waitingMessage), - buildDeltaUpdate(OUTPUT_PATHS.HISTORY_48HR, forecast !== null ? getHistory(forecast, 48) : waitingMessage), - ]; -} - -function getHistory(forecast, hour) { - let history = forecast.history.find((h) => h.hour === hour); - - if(history === null || history.pressure === null) return null; - - return history.pressure.value; + return map.mapProperties(json); } -function buildDeltaUpdate(path, value) { - return { - path: path, - value: value - } -} function clear() { barometerTrend.clear(); - - latest.twd.time = null; - latest.twd.value = null; - latest.position.time = null; - latest.position.value = null; - latest.altitude.value = null; - latest.temperature.value = null; -} - -function preLoad() { - return prepareUpdate(null); + latest = lodash.cloneDeep(TEMPLATE_LATEST); + setAltitudeCorrection(DEFAULT_ALTITUDE_CORRECTION); + setSampleRate(DEFAULT_SAMPLE_RATE); } function hasTWDWithinOneMinute() { - return latest.twd.time !== null ? (Date.now() - latest.twd.time) <= ONE_MINUTE_MILLISECONDS : false; + return latest.twd.time !== null ? (Date.now() - latest.twd.time) <= secondsToMilliseconds(60) : false; } function hasPositionWithinOneMinute() { - return latest.position.time !== null ? (Date.now() - latest.position.time) <= ONE_MINUTE_MILLISECONDS : false; + return latest.position.time !== null ? (Date.now() - latest.position.time) <= secondsToMilliseconds(60) : false; } -function isNortherHemisphere() { +function isNorthernHemisphere() { let position = hasPositionWithinOneMinute() ? latest.position.value : null; if (position === null) return true; //default to northern hemisphere @@ -253,14 +155,13 @@ function isNortherHemisphere() { module.exports = { SUBSCRIPTIONS, - OUTPUT_PATHS, hasTWDWithinOneMinute, - isNortherHemisphere, + isNortherHemisphere: isNorthernHemisphere, hasPositionWithinOneMinute, onDeltasUpdate, clear, - preLoad, - latest, - toKelvinIfCelcius, - toPaIfHpa + //preLoad, + getLatest: () => latest, + setSampleRate, + setAltitudeCorrection } diff --git a/images/pluginConfig.png b/images/pluginConfig.png new file mode 100644 index 0000000..aa44f29 Binary files /dev/null and b/images/pluginConfig.png differ diff --git a/index.js b/index.js index dde8d8a..384d0e9 100644 --- a/index.js +++ b/index.js @@ -1,17 +1,24 @@ 'use strict' +const meta = require('./meta.json'); +const schema = require('./schema.json'); const barometer = require('./barometer'); module.exports = function (app) { var plugin = {}; plugin.id = 'signalk-barometer-trend'; - plugin.name = 'SignalK Barometer Trend'; - plugin.description = 'Calculates barometric trend over time with prediction'; + plugin.name = 'Barometer Trend'; + plugin.description = 'Calculate tendency, trend and weather predictions of barometric pressure'; var unsubscribes = []; plugin.start = function (options, restartPlugin) { - app.debug('Plugin started'); + + barometer.setSampleRate(options.rate * 1000); + app.debug('Sample rate set to ' + options.rate + " seconds"); + barometer.setAltitudeCorrection(options.altitude); + app.debug('Altitude offset set to ' + options.altitude + " metre(s)"); + let localSubscription = { context: '*', subscribe: barometer.SUBSCRIPTIONS @@ -25,8 +32,6 @@ module.exports = function (app) { }, delta => sendDelta(barometer.onDeltasUpdate(delta)) ); - - sendDelta(barometer.preLoad()); }; plugin.stop = function () { @@ -35,22 +40,25 @@ module.exports = function (app) { app.debug('Plugin stopped'); }; - plugin.schema = { - // The plugin schema - }; + plugin.schema = schema[0]; + + function sendDelta(deltaValues) { + if (deltaValues !== null && deltaValues.length > 0) { + + let signalk_delta = { + context: "vessels." + app.selfId, + updates: [ + { + timestamp: new Date().toISOString(), + values: deltaValues, + meta, + } + ] + }; - /** - * - * @param {Array<[{path:path, value:value}]>} messages - */ - function sendDelta(messages) { - app.handleMessage('signalk-barometer-trend', { - updates: [ - { - values: messages - } - ] - }) + //console.debug(JSON.stringify(signalk_delta)); + app.handleMessage(plugin.id, signalk_delta); + } } return plugin; diff --git a/map.js b/map.js new file mode 100644 index 0000000..6a855a2 --- /dev/null +++ b/map.js @@ -0,0 +1,69 @@ +const propertyMap = [ + { signalK: "environment.outside.pressure.trend.tendency", src: (json) => validateProperty(json.trend.tendency) }, + { signalK: "environment.outside.pressure.trend.trend", src: (json) => validateProperty(json.trend.trend) }, + { signalK: "environment.outside.pressure.trend.severity", src: (json) => validateProperty(json.trend.severity) }, + { signalK: "environment.outside.pressure.trend.period", src: (json) => validateProperty(json.trend.period * 60) }, + { signalK: "environment.outside.pressure.trend.period.from", src: (json) => validateProperty(json.trend.from.meta.value) }, + { signalK: "environment.outside.pressure.trend.period.to", src: (json) => validateProperty(json.trend.to.meta.value) }, + + { signalK: "environment.outside.pressure.prediction.pressureOnly", src: (json) => validateProperty(json.predictions.pressureOnly) }, + { signalK: "environment.outside.pressure.prediction.quadrant", src: (json) => validateProperty(json.predictions.quadrant) }, + { signalK: "environment.outside.pressure.prediction.season", src: (json) => validateProperty(json.predictions.season) }, + { signalK: "environment.outside.pressure.prediction.beaufort", src: (json) => validateProperty(json.predictions.beaufort.force) }, + { signalK: "environment.outside.pressure.prediction.beaufort.description", src: (json) => validateProperty(json.predictions.beaufort.description) }, + { signalK: "environment.outside.pressure.prediction.front.tendency", src: (json) => validateProperty(json.predictions.front.tendency) }, + { signalK: "environment.outside.pressure.prediction.front.prognose", src: (json) => validateProperty(json.predictions.front.prognose) }, + { signalK: "environment.outside.pressure.prediction.front.wind", src: (json) => validateProperty(json.predictions.front.wind) }, + + { signalK: "environment.outside.pressure.system", src: (json) => validateProperty(json.system.name) }, + + { signalK: "environment.outside.pressure.1hr", src: (json) => history(json, 1) }, + { signalK: "environment.outside.pressure.3hr", src: (json) => history(json, 3) }, + { signalK: "environment.outside.pressure.6hr", src: (json) => history(json, 6) }, + { signalK: "environment.outside.pressure.12hr", src: (json) => history(json, 12) }, + { signalK: "environment.outside.pressure.24hr", src: (json) => history(json, 24) }, + { signalK: "environment.outside.pressure.48hr", src: (json) => history(json, 48) } +] + +/** + * + * @param {Array} json barometer-trend (npm-package) JSON structure + * @returns [{path: path, value: value}] + */ +function mapProperties(json) { + + const deltaUpdates = []; + propertyMap.forEach((p) => { + try { + let value = (json !== null) ? p.src(json) : defaultPropertyValue; + let deltaUpdate = buildDeltaPath(p.signalK, value); + deltaUpdates.push(deltaUpdate); + } catch { + console.debug("Failed to map property: " + p.signalK); + } + }); + + return deltaUpdates.length > 0 ? deltaUpdates : null; +} + +const history = (json, hour) => { + let pressure = json.history.find((h) => h.hour === hour).pressure; + return pressure !== null ? validateProperty(pressure.meta.value) : null; +} + +const defaultPropertyValue = null; + +function validateProperty(value, defaultValue = defaultPropertyValue) { + return (value !== null || value !== undefined) ? value : defaultValue; +} + +function buildDeltaPath(path, value) { + return { + path: path, + value: value + } +} + +module.exports = { + mapProperties +} \ No newline at end of file diff --git a/meta.json b/meta.json new file mode 100644 index 0000000..6cd055a --- /dev/null +++ b/meta.json @@ -0,0 +1,101 @@ + [ + { + "path": "environment.outside.pressure.1hr", + "value": { + "units": "Pa", + "type": "number", + "description": "Pressure 1 hour ago", + "displayName": "Pressure 1 hour ago", + "shortName": "Pressure 1 hour ago", + "example": 101325 + } + }, + { + "path": "environment.outside.pressure.3hr", + "value": { + "units": "Pa", + "type": "number", + "description": "Pressure 3 hours ago", + "displayName": "Pressure 3 hours ago", + "shortName": "Pressure 3 hours ago", + "example": 101325 + } + }, + { + "path": "environment.outside.pressure.6hr", + "value": { + "units": "Pa", + "type": "number", + "description": "Pressure 6 hours ago", + "displayName": "Pressure 6 hours ago", + "shortName": "Pressure 6 hours ago", + "example": 101325 + } + }, + { + "path": "environment.outside.pressure.12hr", + "value": { + "units": "Pa", + "type": "number", + "description": "Pressure 12 hours ago", + "displayName": "Pressure 12 hours ago", + "shortName": "Pressure 12 hours ago", + "example": 101325 + } + }, + { + "path": "environment.outside.pressure.24hr", + "value": { + "units": "Pa", + "type": "number", + "description": "Pressure 24 hours ago", + "displayName": "Pressure 24 hours ago", + "shortName": "Pressure 24 hours ago", + "example": 101325 + } + }, + { + "path": "environment.outside.pressure.48hr", + "value": { + "units": "Pa", + "type": "number", + "description": "Pressure 48 hours ago", + "displayName": "Pressure 48 hours ago", + "shortName": "Pressure 48 hours ago", + "example": 101325 + } + }, + { + "path": "environment.outside.pressure.trend.period", + "value": { + "units": "s", + "type": "number", + "description": "Trend period, 60 or 180 minutes ", + "displayName": "Trend period", + "shortName": "Trend period", + "example": 3600 + } + }, + { + "path": "environment.outside.pressure.trend.period.from", + "value": { + "units": "Pa", + "type": "number", + "description": "Trend period start pressure", + "displayName": "Period from pressure", + "shortName": "Trend from", + "example": 101325 + } + }, + { + "path": "environment.outside.pressure.trend.period.to", + "value": { + "units": "Pa", + "type": "number", + "description": "Trend period end pressure", + "displayName": "Period to pressure", + "shortName": "Trend to", + "example": 101325 + } + } + ] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 65926b1..1592808 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "signalk-barometer-trend", - "version": "2.1.4", + "version": "2.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -54,9 +54,8 @@ "dev": true }, "barometer-trend": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/barometer-trend/-/barometer-trend-2.2.0.tgz", - "integrity": "sha512-vzI+In3F9sUvi14eg9BTdbpylz58PX7V8MHrQPPBue+62Nd/ZUhaHY6YMjMo4O9bSlP98UjBbEHeBwOLkVQLXg==" + "version": "git+https://github.com/oyve/barometer-trend.git#b3a3eea3ea1d51c61952a68a80c0da296ba751ac", + "from": "git+https://github.com/oyve/barometer-trend.git#dev" }, "binary-extensions": { "version": "2.2.0", @@ -412,6 +411,11 @@ "p-locate": "^5.0.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "log-symbols": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", diff --git a/package.json b/package.json index 53e3861..3dd4c06 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "signalk-barometer-trend", - "version": "2.2.1", + "version": "2.3.0", "description": "Get pressure trend and weather predictions from a barometer over time", "main": "index.js", "scripts": { @@ -32,7 +32,8 @@ }, "homepage": "https://github.com/oyve/signalk-barometer-trend#readme", "dependencies": { - "barometer-trend": "^2.2.0" + "barometer-trend": "^2.2.1", + "lodash": "^4.17.21" }, "devDependencies": { "mocha": "^8.4.0" diff --git a/schema.json b/schema.json new file mode 100644 index 0000000..f854538 --- /dev/null +++ b/schema.json @@ -0,0 +1,17 @@ +[{ + "type": "object", + "properties": { + "rate": { + "title": "Pressure Sample Rate (s)", + "description": "Example: 60, 600, 1200 (1, 10, 20 minutes). Min: 60 (default), Max = 3600", + "type": "number", + "default": 60 + }, + "altitude": { + "title": "Altitude offset (m)", + "description": "Sensor altitude offset to GPS altitude or default zero", + "type": "number", + "default": 0 + } + } +}] \ No newline at end of file diff --git a/test/barometer-test.js b/test/barometer-test.js new file mode 100644 index 0000000..bcbc848 --- /dev/null +++ b/test/barometer-test.js @@ -0,0 +1,347 @@ +'use strict' +const assert = require('assert'); +const barometer = require('../barometer'); +const KELVIN = 273.15; + +describe("Barometer Tests", function () { + describe("onDeltasUpdated", function () { + it("Subscription should equal", function () { + //arrange + barometer.clear(); + let expected = 'environment.outside.pressure'; + //act + let actual = barometer.SUBSCRIPTIONS; + //assert + assert.strictEqual(actual.find((f) => f.path === expected).path, expected); + }); + + it("Pressure should equal", function () { + //arrange + barometer.clear(); + const expectedTendency = "RISING"; + const expectedTrend = "STEADY"; + barometer.onDeltasUpdate(createDeltaMockPressure(101500)); + //act + let actual = barometer.onDeltasUpdate(createDeltaMockPressure(101500 + 3)); + //assert + assert.strictEqual(actual.find((f) => f.path === getPath("trend.tendency")).value, expectedTendency); + assert.strictEqual(actual.find((f) => f.path === getPath("trend.trend")).value, expectedTrend); + assert.strictEqual(actual.find((f) => f.path === getPath("trend.severity")).value, 0); + }); + + it("it should throw an exception", function () { + //arrange + barometer.clear(); + //act + //assert + assert.throws(() => { barometer.onDeltasUpdate(null) }, Error, "Deltas cannot be null"); + }); + + + it("it should be ok", function () { + //arrange + //act + barometer.clear(); + let actual = barometer.onDeltasUpdate(createDeltaMockPressure(300)); + //assert + assert.notStrictEqual(actual, null); + }); + + // describe("preLoad", function () { + // it("it should be waiting", function () { + // //arrange + // //act + // let actual = barometer.preLoad(); + // //assert + // assert.strictEqual(actual.values.find((f) => f.path === getPath("trend.tendency")).value, "Waiting..."); + // }); + // }); + + it("Subscription should equal", function () { + //arrange + barometer.clear(); + let expected = 'environment.outside.pressure'; + //act + let actual = barometer.SUBSCRIPTIONS; + //assert + assert.strictEqual(actual.find((f) => f.path === expected).path, expected); + }); + + it("Has position within one minute", function () { + //arrange + barometer.clear(); + barometer.onDeltasUpdate(createDeltaMockPosition(mockPositionNorthernHemisphere())); + + barometer.onDeltasUpdate(createDeltaMockPressure(101500)); + barometer.onDeltasUpdate(createDeltaMockPressure(101600)); + barometer.onDeltasUpdate(createDeltaMockPressure(101700)); + //act + let actual = barometer.hasPositionWithinOneMinute(); + //assert + assert.strictEqual(actual, true); + }); + + it("Has no position defaults to northern hemisphere", function () { + //arrange + barometer.clear(); + barometer.onDeltasUpdate(createDeltaMockPressure(101500)); + barometer.onDeltasUpdate(createDeltaMockPressure(101600)); + barometer.onDeltasUpdate(createDeltaMockPressure(101700)); + //act + let actual = barometer.isNortherHemisphere(); + //assert + assert.strictEqual(actual, true); + }); + + it("Is northern hemisphere", function () { + //arrange + barometer.clear(); + barometer.onDeltasUpdate(createDeltaMockPosition(mockPositionNorthernHemisphere())); + + barometer.onDeltasUpdate(createDeltaMockPressure(101500)); + barometer.onDeltasUpdate(createDeltaMockPressure(101600)); + barometer.onDeltasUpdate(createDeltaMockPressure(101700)); + //act + let actual = barometer.isNortherHemisphere(); + //assert + assert.strictEqual(actual, true); + }); + + it("Is southern hemisphere", function () { + //arrange + barometer.clear(); + barometer.onDeltasUpdate(createDeltaMockPosition(mockPositionSouthernHemisphere())); + + barometer.onDeltasUpdate(createDeltaMockPressure(101500)); + barometer.onDeltasUpdate(createDeltaMockPressure(101600)); + barometer.onDeltasUpdate(createDeltaMockPressure(101700)); + //act + let actual = barometer.isNortherHemisphere(); + //assert + assert.strictEqual(actual, false); + }); + + it("Has TWD within one minute", function () { + //arrange + barometer.clear(); + barometer.onDeltasUpdate(createDeltaMockWindDirection(225)); + + barometer.onDeltasUpdate(createDeltaMockPressure(101500)); + barometer.onDeltasUpdate(createDeltaMockPressure(101600)); + barometer.onDeltasUpdate(createDeltaMockPressure(101700)); + //act + let actual = barometer.hasTWDWithinOneMinute(); + //assert + assert.strictEqual(actual, true); + }); + + it("Has not TWD within one minute", function () { + //arrange + barometer.clear(); + + barometer.onDeltasUpdate(createDeltaMockPressure(101500)); + barometer.onDeltasUpdate(createDeltaMockPressure(101600)); + barometer.onDeltasUpdate(createDeltaMockPressure(101700)); + //act + let actual = barometer.hasTWDWithinOneMinute(); + //assert + assert.strictEqual(actual, false); + }); + + it("Has temperature", function () { + //arrange + const expected = 30 + KELVIN; + barometer.clear(); + //act + barometer.onDeltasUpdate(createDeltaMockTemperature(expected)); + //assert + assert.strictEqual(barometer.getLatest().temperature.value, expected); + }); + + it("Has altitude", function () { + //arrange + const expected = 100; + barometer.clear(); + //act + barometer.onDeltasUpdate(createDeltaMockAltitude(expected)); + //assert + assert.strictEqual(barometer.getLatest().altitude.value, expected); + }); + }); + + describe("System Tests", function () { + it("System is correct", function () { + //arrange + barometer.clear(); + const expected = "Normal"; + barometer.onDeltasUpdate(createDeltaMockPressure(101549)); + //act + let actual = barometer.onDeltasUpdate(createDeltaMockPressure(101500)); + //assert + assert.strictEqual(actual.find((f) => f.path === getPath("system")).value, expected); + + }); + }); + + describe("Set Sample Rate", function () { + it("It should equal", function () { + //arrange + barometer.clear(); + let expected = 80; + //act + var actual = barometer.setSampleRate(80); + //assert + assert.strictEqual(actual, expected); + }); + it("It should equal under threshold", function () { + //arrange + barometer.clear(); + let expected = 3600 * 1000; + //act + var actual = barometer.setSampleRate(3601); + //assert + assert.strictEqual(actual, expected); + }); + it("It should equal above threshold", function () { + //arrange + barometer.clear(); + let expected = 60 * 1000; + //act + var actual = barometer.setSampleRate(59); + //assert + assert.strictEqual(actual, expected); + }); + }); + + describe("Set Altitude Correction", function () { + it("It should equal positive", function () { + //arrange + barometer.clear(); + let expected = 104; + //act + barometer.setAltitudeCorrection(4); + barometer.onDeltasUpdate(createDeltaMockAltitude(100)); + let actual = barometer.getLatest().altitude.value; + //assert + assert.strictEqual(actual, expected); + }); + + it("It should equal negative", function () { + //arrange + barometer.clear(); + let expected = 96; + //act + barometer.setAltitudeCorrection(-4); + barometer.onDeltasUpdate(createDeltaMockAltitude(100)); + let actual = barometer.getLatest().altitude.value; + //assert + assert.strictEqual(actual, expected); + }); + + it("It should not equal", function () { + //arrange + barometer.clear(); + let expected = 100; + //act + barometer.setAltitudeCorrection(null); + barometer.setAltitudeCorrection(undefined); + barometer.onDeltasUpdate(createDeltaMockAltitude(100)); + let actual = barometer.getLatest().altitude.value; + //assert + assert.strictEqual(actual, expected); + }); + }); +}); + +function getPath(path) { + return "environment.outside.pressure." + path; +} + +function createDeltaMockPressure(value) { + return { + updates: [ + { + values: [ + { + path: 'environment.outside.pressure', + value: value + } + ] + } + ] + } +} + +function createDeltaMockTemperature(temperature) { + return { + updates: [ + { + values: [ + { + path: 'environment.outside.temperature', + value: temperature + } + ] + } + ] + } +} + +function createDeltaMockAltitude(altitude) { + return { + updates: [ + { + values: [ + { + path: 'navigation.gnss.antennaAltitude', + value: altitude + } + ] + } + ] + } +} + +function createDeltaMockWindDirection(value) { + return { + updates: [ + { + values: [ + { + path: 'environment.wind.directionTrue', + value: value + } + ] + } + ] + } +} + +function createDeltaMockPosition(position) { + return { + updates: [ + { + values: [ + { + path: 'navigation.position', + value: position + } + ] + } + ] + } +} + +function mockPositionNorthernHemisphere() { + return { + "longitude": -61.59, + "latitude": 15.84 + } +} + +function mockPositionSouthernHemisphere() { + return { + "longitude": -61.59, + "latitude": -15.84 + } +} \ No newline at end of file diff --git a/test/index-test.js b/test/index-test.js index 05a49c3..3e5040c 100644 --- a/test/index-test.js +++ b/test/index-test.js @@ -1,341 +1,14 @@ -'use strict' -const assert = require('assert'); -const barometer = require('../barometer'); -const KELVIN = 273.15; - -describe("Barometer Tests", function () { - describe("onDeltasUpdated", function () { - it("Subscription should equal", function () { - //arrange - barometer.clear(); - let expected = 'environment.outside.pressure'; - //act - let actual = barometer.SUBSCRIPTIONS; - //assert - assert.strictEqual(actual.find((f) => f.path === expected).path, expected); - }); - - it("Pressure should equal", function () { - //arrange - barometer.clear(); - const expectedTendency = "RISING"; - const expectedTrend = "STEADY"; - barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - //act - let actual = barometer.onDeltasUpdate(createDeltaMockPressure(101500 + 3)); - //assert - assert.strictEqual(actual.find((f) => f.path === barometer.OUTPUT_PATHS.TREND_TENDENCY).value, expectedTendency); - assert.strictEqual(actual.find((f) => f.path === barometer.OUTPUT_PATHS.TREND_TREND).value, expectedTrend); - assert.strictEqual(actual.find((f) => f.path === barometer.OUTPUT_PATHS.TREND_SEVERITY).value, 0); - }); - - it("it should throw an exception", function () { - //arrange - barometer.clear(); - //act - //assert - assert.throws(() => { barometer.onDeltasUpdate(null) }, Error, "Deltas cannot be null"); - }); - - - it("it should be ok", function () { - //arrange - //act - barometer.clear(); - let actual = barometer.onDeltasUpdate(createDeltaMockPressure(300)); - //assert - assert.notStrictEqual(actual, null); - }); - - describe("preLoad", function () { - it("it should be waiting", function () { - //arrange - //act - let actual = barometer.preLoad(); - //assert - assert.strictEqual(actual.find((f) => f.path === barometer.OUTPUT_PATHS.TREND_TENDENCY).value, "Waiting.."); - }); - }); - - it("Subscription should equal", function () { - //arrange - barometer.clear(); - let expected = 'environment.outside.pressure'; - //act - let actual = barometer.SUBSCRIPTIONS; - //assert - assert.strictEqual(actual.find((f) => f.path === expected).path, expected); - }); - - it("Has position within one minute", function () { - //arrange - barometer.clear(); - barometer.onDeltasUpdate(createDeltaMockPosition(mockPositionNorthernHemisphere())); - - barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - barometer.onDeltasUpdate(createDeltaMockPressure(101600)); - barometer.onDeltasUpdate(createDeltaMockPressure(101700)); - //act - let actual = barometer.hasPositionWithinOneMinute(); - //assert - assert.strictEqual(actual, true); - }); - - it("Has no position defaults to northern hemisphere", function () { - //arrange - barometer.clear(); - barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - barometer.onDeltasUpdate(createDeltaMockPressure(101600)); - barometer.onDeltasUpdate(createDeltaMockPressure(101700)); - //act - let actual = barometer.isNortherHemisphere(); - //assert - assert.strictEqual(actual, true); - }); - - it("Is northern hemisphere", function () { - //arrange - barometer.clear(); - barometer.onDeltasUpdate(createDeltaMockPosition(mockPositionNorthernHemisphere())); - - barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - barometer.onDeltasUpdate(createDeltaMockPressure(101600)); - barometer.onDeltasUpdate(createDeltaMockPressure(101700)); - //act - let actual = barometer.isNortherHemisphere(); - //assert - assert.strictEqual(actual, true); - }); - - it("Is southern hemisphere", function () { - //arrange - barometer.clear(); - barometer.onDeltasUpdate(createDeltaMockPosition(mockPositionSouthernHemisphere())); - - barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - barometer.onDeltasUpdate(createDeltaMockPressure(101600)); - barometer.onDeltasUpdate(createDeltaMockPressure(101700)); - //act - let actual = barometer.isNortherHemisphere(); - //assert - assert.strictEqual(actual, false); - }); - - it("Has TWD within one minute", function () { - //arrange - barometer.clear(); - barometer.onDeltasUpdate(createDeltaMockWindDirection(225)); - - barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - barometer.onDeltasUpdate(createDeltaMockPressure(101600)); - barometer.onDeltasUpdate(createDeltaMockPressure(101700)); - //act - let actual = barometer.hasTWDWithinOneMinute(); - //assert - assert.strictEqual(actual, true); - }); - - it("Has not TWD within one minute", function () { - //arrange - barometer.clear(); - - barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - barometer.onDeltasUpdate(createDeltaMockPressure(101600)); - barometer.onDeltasUpdate(createDeltaMockPressure(101700)); - //act - let actual = barometer.hasTWDWithinOneMinute(); - //assert - assert.strictEqual(actual, false); - }); - - it("Has temperature", function () { - //arrange - const expected = 30 + KELVIN; - barometer.clear(); - //act - barometer.onDeltasUpdate(createDeltaMockTemperature(expected)); - //assert - assert.strictEqual(barometer.latest.temperature.value, expected); - }); - - it("Has altitude", function () { - //arrange - const expected = 100; - barometer.clear(); - //act - barometer.onDeltasUpdate(createDeltaMockAltitude(expected)); - //assert - assert.strictEqual(barometer.latest.altitude.value, expected); - }); - - it("Has altitude", function () { - //arrange - const expected = 100; - barometer.clear(); - //act - barometer.onDeltasUpdate(createDeltaMockAltitude(expected)); - //assert - assert.strictEqual(barometer.latest.altitude.value, expected); - }); - - it("To Kelvin if Celcius", function () { - //arrange - const expected = 30 + KELVIN; - barometer.clear(); - //act - let actual = barometer.toKelvinIfCelcius(30); - //assert - assert.strictEqual(actual, expected); - }); - - it("Not to Kelvin if Kelvin", function () { - //arrange - const expected = KELVIN; - barometer.clear(); - //act - let actual = barometer.toKelvinIfCelcius(expected); - //assert - assert.strictEqual(actual, expected); - }); - - it("To Pa if hPa", function () { - //arrange - const expected = 101513; - barometer.clear(); - //act - let actual = barometer.toPaIfHpa(1015.13); - //assert - assert.strictEqual(actual, expected); - }); - - it("Not to Pa if Pa", function () { - //arrange - const expected = 101513; - barometer.clear(); - //act - let actual = barometer.toPaIfHpa(expected); - //assert - assert.strictEqual(actual, expected); - }); - }); - - describe("System Tests", function () { - it("System is correct", function () { - //arrange - barometer.clear(); - const expected = "Normal"; - barometer.onDeltasUpdate(createDeltaMockPressure(101549)); - //act - let actual = barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - //assert - assert.strictEqual(actual.find((f) => f.path === barometer.OUTPUT_PATHS.SYSTEM).value, expected); - - }); - }); - - describe("ASL Tests", function () { - it("ASL is correct", function () { - //arrange - barometer.clear(); - const expectedASL = 102649; - barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - barometer.onDeltasUpdate(createDeltaMockTemperature(30)); - barometer.onDeltasUpdate(createDeltaMockAltitude(100)); - //act - let actual = barometer.onDeltasUpdate(createDeltaMockPressure(101500)); - //assert - assert.strictEqual(actual.find((f) => f.path === barometer.OUTPUT_PATHS.ASL).value, expectedASL); - - }); - }); - -}); - -function createDeltaMockPressure(value) { - return { - updates: [ - { - values: [ - { - path: 'environment.outside.pressure', - value: value - } - ] - } - ] - } -} - -function createDeltaMockTemperature(temperature) { - return { - updates: [ - { - values: [ - { - path: 'environment.outside.temperature', - value: temperature - } - ] - } - ] - } -} - -function createDeltaMockAltitude(altitude) { - return { - updates: [ - { - values: [ - { - path: 'navigation.gnss.antennaAltitude', - value: altitude - } - ] - } - ] - } -} - -function createDeltaMockWindDirection(value) { - return { - updates: [ - { - values: [ - { - path: 'environment.wind.directionTrue', - value: value - } - ] - } - ] - } -} - -function createDeltaMockPosition(position) { - return { - updates: [ - { - values: [ - { - path: 'navigation.position', - value: position - } - ] - } - ] - } -} - -function mockPositionNorthernHemisphere() { - return { - "longitude": -61.59, - "latitude": 15.84 - } -} - -function mockPositionSouthernHemisphere() { - return { - "longitude": -61.59, - "latitude": -15.84 - } -} \ No newline at end of file +const index = require('../index'); + +// describe("Index Tests", function () { +// describe("app", function () { +// it("it should equal", function () { +// //arrange + +// //act + +// //assert + +// }); +// }); +// }); \ No newline at end of file diff --git a/test/map-test.js b/test/map-test.js new file mode 100644 index 0000000..54835bc --- /dev/null +++ b/test/map-test.js @@ -0,0 +1,94 @@ +'use strict' +const assert = require('assert'); +const { getPressureAverage } = require('barometer-trend/utils'); +const barometer = require('../barometer'); +const map = require("../map"); + +describe("Barometer Tests", function () { + describe("History", function () { + it("It should equal 1hr", function () { + //arrange + let expected = 102110; + //act + let actual = map.mapProperties(jsonMock); + //assert + assert.strictEqual(actual.find((m) => m.path === 'environment.outside.pressure.1hr').value, expected); + }); + it("It should equal 3hr", function () { + //arrange + let expected = 102210; + //act + let actual = map.mapProperties(jsonMock); + //assert + assert.strictEqual(actual.find((m) => m.path === 'environment.outside.pressure.3hr').value, expected); + }); + it("It should equal 6hr", function () { + //arrange + let expected = 102310; + //act + let actual = map.mapProperties(jsonMock); + //assert + assert.strictEqual(actual.find((m) => m.path === 'environment.outside.pressure.6hr').value, expected); + }); + it("It should equal 12hr", function () { + //arrange + let expected = 102410; + //act + let actual = map.mapProperties(jsonMock); + //assert + assert.strictEqual(actual.find((m) => m.path === 'environment.outside.pressure.12hr').value, expected); + }); + it("It should equal 24hr", function () { + //arrange + let expected = 102510; + //act + let actual = map.mapProperties(jsonMock); + //assert + assert.strictEqual(actual.find((m) => m.path === 'environment.outside.pressure.24hr').value, expected); + }); + it("It should equal 48hr", function () { + //arrange + let expected = 102610; + //act + let actual = map.mapProperties(jsonMock); + //assert + assert.strictEqual(actual.find((m) => m.path === 'environment.outside.pressure.48hr').value, expected); + }); + }); +}); + + +const pressureMock = (pressure = 102100) => { + return { + datetime: new Date(), + value: pressure, + meta: { + value: pressure + 10, + altitude: 50, + temperature: 301, + twd: null + } + }; +} + +const jsonMock = { + trend: { + tendency: 'RISING', + trend: 'QUICKLY', + severity: 3, + from: pressureMock(), + to: pressureMock(102600), + period: 10800 + }, + predictions: { + pressureOnly: "Pressure Only" + }, + history: [ + { hour: 1, pressure: pressureMock(102100) }, + { hour: 3, pressure: pressureMock(102200) }, + { hour: 6, pressure: pressureMock(102300) }, + { hour: 12, pressure: pressureMock(102400) }, + { hour: 24, pressure: pressureMock(102500) }, + { hour: 48, pressure: pressureMock(102600) }, + ] +}