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
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