# Formulas used to convert WeatherFlow JSON data

These are the formulas I use to convert the UDP values to a human understandable value.

Many of these came from WeatherFlow.

``````//Weather Formulas

const myfile = {"alias": "WeatherFormulas", "version": "1.6.12.005", "addtopm2": "no"};

if (typeof require != 'undefined') {
const util = require('./util');
}
(function () { 'use strict';

// Vapor Pressure //
function _calcVaporPressure(T) {
// (tmep in C)
T = parseFloat(T);
var a = (7.5 * T) / (237.3 + T);
var Es = 6.1078 * Math.pow(10, a);
return Es;
}

function _convertCToF(T) {
T = parseFloat(T);
var r = 1.8 * T + 32;
return Math.round(100 * r) / 100;
};

// e.DistanceValue.prototype._convertTo
function _convertDistance(D, U) {
// (distance, unit)
D = parseFloat(D);
if (U == 'mi') {
D = D * .621371;
}
return D.toFixed(2);
};

// e.TemperatureValue.convertFToC
function _convertFToC(T) {
T = parseFloat(T);
var r = (T - 32) / 1.8;
return Math.round(100 * r) / 100;
};

var WeatherCalc = {};

// Air Density //
WeatherCalc.calcAirDensity = function(T, P, Dp) {
// (air temp in C, sea level pressure, dew point)
// var d = (P * 100) / (287.05 * (T + 273.15));
T = parseFloat(T);
P = parseFloat(P);
Dp = parseFloat(Dp)
var Es = _calcVaporPressure(Dp),
Rv = 461.4964,
Rd = 287.0531,
tk = T + 273.15,
pv = Es * 100,
pd = (P - Es) * 100,
d = (pv / (Rv * tk) ) + (pd / (Rd * tk) );
return d.toFixed(5);
},
// Delta T //
WeatherCalc.calcDeltaT = function(T, WB) {
// (air temp in C, web bulb in C)
T = parseFloat(T);
WB = parseFloat(WB);
return d = (T - WB).toFixed(2);
},
// Dew Point Temperature //
// e.Observations.prototype._getDewPoint
WeatherCalc.calcDewPoint = function(T, RH) {
//(air temp in C, humidity)
T = parseFloat(T);
RH = parseFloat(RH);
var DP = 243.04 * (Math.log(RH / 100) + 17.625 * T / (243.04 + T)) / (17.625 - Math.log(RH / 100) - 17.625 * T / (243.04 + T));
return DP.toFixed(2);
},
// Feels Like Temperature //
// If temperature >= 80°F =  Heat Index.
// If temperature < 50°F = Wind Chill.
// this formula is not complete
// e.DerivedValues.feelsLike
WeatherCalc.calcFeelsLike = function(T, RH) {
// (air temp in C, humidity)
var F = _convertCToF(T);
RH = parseInt(RH, 10);
if (RH < 40 || F < 80) return T;
var r = 61 + 1.2 * (F - 68) + .094 * RH,
s = .5 * (F + r),
n = 0;
if (s > 79) {
if (n = 2.04901523 * F - 42.379 + 10.14333127 * RH - .22475541 * F * RH - 6.83783 * Math.pow(10, -3) * Math.pow(F, 2) - 5.481717 * Math.pow(10, -2) * Math.pow(RH, 2) + 1.22874 * Math.pow(10, -3) * Math.pow(F, 2) * RH + 8.5282 * Math.pow(10, -4) * F * Math.pow(RH, 2) - 1.99 * Math.pow(10, -6) * Math.pow(F, 2) * Math.pow(i, 2), RH <= 13 && F >= 80 && F < 112) {
var o = (13 - i) / 4,
l = Math.sqrt((17 - Math.abs(F - 95)) / 17);
n -= o * l;
} else if (RH > 85 && F >= 80 && F <= 87) {
var c = (RH - 85) / 10,
u = (87 - F) / 5;
n += c * u;
}
} else n = s;
var FL = _convertFToC(n);
return FL;
},
// Heat Index Temperature //
// e.Observations.prototype._getHeatIndex
WeatherCalc.calcHeatIndex = function(T, RH) {
// (air temp in C, humidity)
var F = _convertCToF(T);
RH = parseInt(RH, 10);
if (RH < 40 || F < 80) return T;
var r = 61 + 1.2 * (F - 68) + .094 * RH,
s = .5 * (F + r),
n = 0;
if (s > 79) {
if (n = 2.04901523 * F - 42.379 + 10.14333127 * RH - .22475541 * F * RH - 6.83783 * Math.pow(10, -3) * Math.pow(F, 2) - 5.481717 * Math.pow(10, -2) * Math.pow(RH, 2) + 1.22874 * Math.pow(10, -3) * Math.pow(F, 2) * RH + 8.5282 * Math.pow(10, -4) * F * Math.pow(RH, 2) - 1.99 * Math.pow(10, -6) * Math.pow(F, 2) * Math.pow(i, 2), RH <= 13 && F >= 80 && F < 112) {
var o = (13 - i) / 4,
l = Math.sqrt((17 - Math.abs(F - 95)) / 17);
n -= o * l;
} else if (RH > 85 && F >= 80 && F <= 87) {
var c = (RH - 85) / 10,
u = (87 - F) / 5;
n += c * u;
}
} else n = s;
return _convertFToC(n);
},
// Pressure Trend //
WeatherCalc.calcPressureTrend = function(sn, Z) {
var	l,
r,
s,
x,
time,
diff,
old = [],
trend;
l = UDPPres[sn].S.length;
// System.LogHigh('Pressure');
// find the 180th newest record
if (l < 181) {
r = 0;
s = '*';
} else {
r = l - 181;
s = '';
}
time = (Z[0] - UDPPres[sn].S[r][0]);
old = UDPPres[sn].S[r];
diff = (Z[1] - old[1]);
if (r == 0) {
x = (10800 / time);
diff = (diff == 0) ? 0: (diff * x);
}
a = Math.abs(diff);
trend = (diff >= 1) ? 'Rising' : (diff <= -1) ? 'Falling' : 'Steady';
if (a > 2) {
trend = 'Rapid ' + trend;
}
trend += s;
//System.LogHigh('PressureTrend');
//System.LogHigh('l = ' + l);
//System.LogHigh('r = ' + r);
//System.LogHigh('AR = ' + Z[0]);
//System.LogHigh('UDP = ' + UDPPres[sn].S[r][0]);
//System.LogHigh('diff = ' + Z[1] + ' - ' + old[1] + ' = ' + diff.toFixed(2));
//System.LogHigh('time = ' + time);
//System.LogHigh('x = ' + x);
//System.LogHigh('trend = ' + trend);
return {
trend: trend,
value: diff
};
},
// Temperature Trend //
WeatherCalc.calcTemperatureTrend = function(sn, Z) {
var	l,
r,
s,
x,
time,
diff,
old = [],
trend,
value;
l = UDPTemp[sn].S.length;
// System.LogHigh('Temp');
// find the 60th newest record
if (l < 61) {
r = 0;
s = '*';
} else {
r = l - 61;
s = '';
}
time = (Z[0] - UDPTemp[sn].S[r][0]);
old = UDPTemp[sn].S[r];
diff = (Z[2] - old[1]);
if (r == 0) {
x = (3600 / time);
diff = (diff == 0) ? 0: (diff * x);
}
a = Math.abs(diff);
trend = (diff >=5) ? 'Rising' : (diff <= -5) ? 'Falling' : 'Steady';
if (a > 10) {
trend = 'Rapid ' + trend;
}
trend += s;
//System.LogHigh('TempTrend');
//System.LogHigh('l = ' + l);
//System.LogHigh('r = ' + r);
//System.LogHigh('AR = ' + Z[0]);
//System.LogHigh('UDP = ' + UDPTemp[sn].S[r][0]);
//System.LogHigh('diff = ' + Z[2] + ' - ' + old[2] + ' = ' + diff.toFixed(2));
//System.LogHigh('time = ' + time);
//System.LogHigh('x = ' + x);
//System.LogHigh('value = ' + value);
//System.LogHigh('trend = ' + trend);
return {
trend: trend,
value: diff
};
},
// Sea Level Pressure //
// e.PressureValue.prototype._convertToSeaLevel
WeatherCalc.calcSeaLevel = function(A, P) {
// (altitude in meters, local pressure in mb)
A = parseFloat(A);
P = parseFloat(P);
var
a = 9.80665,
i = 287.05,
r = .0065,
s = 1013.25,
n = 288.15,
l = a / (i * r),
c = i * r / a,
u = Math.pow(1 + Math.pow(s / P, c) * (r * A / n), l),
d = (P * u);
return d.toFixed(1);
},
// Wet Bulb Temperatre //
// wetbulb = calcwetbulb(Edifference,Twguess,Ctemp,MBpressure,E2,previoussign,incr);
// from http://www.weather.gov/epz/wxcalc_rh
WeatherCalc.calcWetBulb = function(T, RH, P) {
// (temp in C, humidity, station pressure)
T = parseFloat(T);
RH = parseFloat(RH);
P = parseFloat(P);
var Edifference = 1,
Twguess = 0,
previoussign = 1,
incr = 10,
Es = 6.112 * Math.exp(17.67 * T / (T + 243.5)),
E2 = Es * (RH / 100);
outerloop:
while (Math.abs(Edifference) > 0.005) {
Ewguess = 6.112 * Math.exp((17.67 * Twguess) / (Twguess + 243.5));
Eguess = Ewguess - P * (T - Twguess) * 0.00066 * (1 + (0.00115 * Twguess));
Edifference = E2 - Eguess;
if (Edifference == 0) {
break outerloop;
} else {
if (Edifference < 0) {
cursign = -1;
if (cursign != previoussign) {
previoussign = cursign;
incr = incr / 10;
} else {
incr = incr;
}
} else {
cursign = 1;
if (cursign != previoussign) {
previoussign = cursign;
incr = incr / 10;
} else {
incr = incr;
}
}
}
Twguess = Twguess + incr * previoussign;
}
return Twguess.toFixed(2);
},
// Wind and Direction //
WeatherCalc.calcWind = function(d) {
var i,
EW_Vector = 0,
NS_Vector = 0,
gust = 0,
lull = 999,
s = 0;
for (i = 0; i < d.length; i++) {
s += d[i][1];
EW_Vector += Math.sin(0.01745329252 * d[i][2]) * d[i][1];
NS_Vector += Math.cos(0.01745329252 * d[i][2]) * d[i][1];
if (d[i][1] > gust) gust = d[i][1];
if (d[i][1] < lull) lull = d[i][1];
}
var speed = s / d.length;
var EW_Average = (EW_Vector / d.length) * -1;
var NS_Average = (NS_Vector / d.length) * -1;
var dir = (Math.atan2(EW_Average, NS_Average) / 0.01745329252);
var direction = Math.round( dir > 180 ? dir -= 180 : dir += 180 );
return {
date: d[0][0],
direction: direction.toString(),
speed: speed,
lull: lull,
gust: gust
};
},
// Wind Chill Temperature //
// e.Observations.prototype._getWindChill
WeatherCalc.calcWindChill = function(T, W) {
// (air temp, wind speed)
//Debug('temp = ' + T);
//Debug('wind = ' + W);
var F = _convertCToF(T);
var V = WeatherCalc.convertWindSpeed(W, 'mph');
if (V < 5 || F > 50) return parseFloat(T);
var WC = 35.74 + (0.6215 * F) - ( 35.75 * Math.pow(V, .16) ) + ( 0.4275 * F * Math.pow(V, .16) );
return _convertFToC(WC);
},
// Convert Functions //
// e.SWUser.prototype.userAirDensityDisplay
WeatherCalc.convertAirDensity = function(T, U) {
// (air temp, unit)
T = parseFloat(T);
if (U == 'imperial') {
var i = .062428 * T;
return i.toFixed(5);
}
return T;
},
// e.SWUser.prototype.userDeltaTDisplay
WeatherCalc.convertDeltaT = function(T, U) {
// (temp in C, unit)
T = parseFloat(T);
if (U == 'f') {
T = Math.abs(1.8 * T);
}
return T.toFixed(1);
},
// https://stackoverflow.com/questions/37893131/how-to-convert-lat-long-from-decimal-degrees-to-dms-format
WeatherCalc.convertLatLongDecimalToDMS = function(coordinate) {
var dms = {};
var absolute = Math.abs(coordinate);
var degrees = Math.floor(absolute);
var minutesNotTruncated = (absolute - degrees) * 60;
var minutes = Math.floor(minutesNotTruncated);
var seconds = Math.floor((minutesNotTruncated - minutes) * 60);
var hundreths = parseInt((seconds / 60) * 100);

dms['coordinate'] = coordinate;
dms['degrees'] = degrees;
dms['minutes'] = minutes;
dms['seconds'] = seconds;
dms['hundreths'] = hundreths;
return dms;
},
// e.LightningDistanceValue.prototype._convertToText
WeatherCalc.convertLightningDistance = function(D, U) {
// (distance)
D = parseFloat(D);
if (D == 0 || isNaN(D)) return '---';
if (U = 'mi') {
D = _convertDistance(D, U);
}
D = parseInt(D);
/*
return null != this.value && (
this.value > 34 ? (t.graphMin = 20, t.graphMax = 25, t.value = Math.round(new e.DistanceValue(35, this.units).displayValue()), t.symbol = ">") :
this.value > 20 ? (t.graphMin = 15, t.graphMax = 20, t.value = Math.round(new e.DistanceValue(35, this.units).displayValue()), t.symbol = "&#x2264;") :
this.value > 10 ? (t.graphMin = 10, t.graphMax = 15, t.value = Math.round(new e.DistanceValue(20, this.units).displayValue()), t.symbol = "&#x2264;") :
this.value > 5 ? (t.graphMin = 5, t.graphMax = 10, t.value = Math.round(new e.DistanceValue(10, this.units).displayValue()), t.symbol = "&#x2264;") :
(t.graphMin = 0, t.graphMax = 5, t.value = Math.round(new e.DistanceValue(5, this.units).displayValue()), t.symbol = "&#x2264;")), t

if (D > 34) {
i = 35.0;
} else if (D > 29) {
i = 29.9;
} else if (D > 24) {
i = 24.9;
} else if (D > 19) {
i = 19.9;
} else if (D > 14) {
i = 14.9;
} else if (D > 9) {
i = 9.1;
} else {
i = 4.9;
}
*/
return D;
},
// e.DistanceValue.prototype._convertTo
WeatherCalc.convertMeasure = function(D, U) {
// (distance, unit)
D = parseFloat(D);
if (U == 'ft') {
D = D * 3.28084;
}
return D.toFixed(2);
},
WeatherCalc.convertMoonPhase8 = function(D) {
D = D * 1000;
var e = Math.floor((D / 125));
return (e % 8);
},
WeatherCalc.convertMoonPhase16 = function(D) {
D = D * 1000;
var e = Math.floor((D / 62.5));
return (e % 16);
},
// e.PrecipValue.prototype._convertTo
WeatherCalc.convertPrecip = function(T, U) {
// (precip, unit)
var t = parseFloat(T);
var i = t;
switch (U) {
case 'in':
i = .0393701 * t;
return parseFloat(i.toFixed(3));
break;
case 'cm':
i = .1 * t;
return parseFloat(i.toFixed(1));
break;
default:
return i;
break;
}
},
// e.PrecipValue.prototype._convertTo
WeatherCalc.convertPrecipRate = function(T, I, U) {
// (precip, unit)
t = parseFloat(T);
var i = t;
switch (U) {
case 'in':
i = .0393701 * t;
return (i * (60 / I)).toFixed(3);
break;
case 'cm':
i = .1 * t;
return i.toFixed(1);
break;
default:
return i;
break;
}
},
WeatherCalc.convertPrecipType = function(T) {
// (precip, unit)
var i;
switch (T) {
case 0:
i = 'None';
break;
case 1:
i = 'Rain';
break;
case 2:
i = 'Hail';
break;
default:
i = '---';
}
return i;
},
// e.PressureValue.prototype._convert
WeatherCalc.convertPressure = function(P, U) {
// (pressure, unit)
if (null == P) return null;
P = parseFloat(P);
if (U == 'inhg') {
return (.0295301 * P).toFixed(3);
} else {
return P.toFixed(1);
}
},
// e.TemperatureValue.prototype.convertTo
WeatherCalc.convertTemp = function(T, U) {
// (air temp, unit)
T = parseFloat(T);
if (U == 'f') {
T =_convertCToF(T);
}
return parseFloat(T.toFixed(1));
},
WeatherCalc.convertUcaseFirst = function(s) {
// (string)
s = s.charAt(0).toUpperCase() + s.slice(1);;
return s;
},
WeatherCalc.convertUptime = function(Time) {
var day,
hour,
minute,
second,
temp,
time = parseInt(Time, 10);
// Debug('time = ' + time);
temp = time / 86400;
day = parseInt(temp, 10);
// Debug('Day = ' + day);
time = time - (86400 * day);
temp = time / 3600;
hour = parseInt(temp, 10);
time = time - (3600 * hour);
temp = time / 60;
minute = parseInt(temp, 10);
time = time - (60 * minute);
temp = time;
second = parseInt(temp, 10);
temp = '';
if (day > 0) {
temp = day.toString()
temp += 'd ';
}
temp += hour.toString() + 'h ' + minute.toString() + 'm ' + second.toString() + 's';
return temp;
},
WeatherCalc.convertWindDirection16 = function(D) {
var e = Math.floor((D / 22.5) + 0.5);
return (e % 16);
},
WeatherCalc.convertWindDirection32 = function(D) {
var e = Math.floor((D / 11.25) + 0.25);
return (e % 32);
},
// e.WindSpeedValue.prototype._convertTo
WeatherCalc.convertWindSpeed = function(t, u) {
//(speed, unit)
this.value = t;
var i = this.value;
switch (u) {
case 'mph':
i = 2.2369362920544 * this.value;
break;
case 'kph':
i = 3.6 * this.value;
break;
case 'kts':
i = 1.9438 * this.value;
break;
case 'bft':
i = this.value < .3 ? 0 : this.value < 1.6 ? 1 : this.value < 3.5 ? 2 : this.value < 5.5 ? 3 : this.value < 8 ? 4 : this.value < 10.8 ? 5 : this.value < 13.9 ? 6 : this.value < 17.2 ? 7 : this.value < 20.8 ? 8 : this.value < 24.5 ? 9 : this.value < 28.5 ? 10 : this.value < 32.7 ? 11 : this.value >= 32.7 ? 12 : 0;
break;
case 'lfm':
i = 2.2369362920544 * this.value * 88;
}
return parseFloat(i).toFixed(1);
},
WeatherCalc.formatLightningDistance = function(D, U) {
D = parseFloat(D);
if (D == 0) return '---';
var d = Math.ceil(D),
i = '> ';
if (d > D) {
i = '< ';
}
if (U = 'mi') {
D = _convertDistance(D);
}
return (i + d + ' ' + U)
},
// Compass //
WeatherCalc.ToCompass16 = function(num) {
var arr = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"];
return arr[num];
},
WeatherCalc.ToCompass32 = function(num) {
var arr = ["N", "NbE", "NNE", "NEbN", "NE", "NEbE", "ENE", "EbN", "E", "EbS", "ESE", "SEbE", "SE", "SEbS", "SSE", "SbE", "S", "SbW", "SSW", "SWbS", "SW", "SWbW", "WSW", "WbS", "W", "WbN", "WNW", "NWbW", "NW", "NWbN", "NNW", "NbW"];
return arr[num];
},
WeatherCalc.ToMoonPhase8 = function(num) {
var arr = ["New Moon", "Waxing Crescent", "First Quarter", "Waxing Gibbous", "Full Moon", "Waning Gibbous", "Last Quarter", "Waning Crescent"];
return arr[num];
},
WeatherCalc.ToMoonPhase16 = function(num) {
var arr = ["New Moon", "New Moon >> Waxing Crescent", "Waxing Crescent", "Waxing Crescent >> First Quarter", "First Quarter", "First Quarter >> Waxing Gibbous", "Waxing Gibbous", "Waxing Gibbous >> Full Moon", "Full Moon", "Full Moon >> Waning Gibbous", "Waning Gibbous", "Waning Gibbous >> Last Quarter", "Last Quarter", "Last Quarter >> Waning Crescent", "Waning Crescent", "Waning Crescent >> New Moon"];
return arr[num];
},
WeatherCalc.GetCompass16 = function(deg) {
var num = WeatherCalc.convertWindDirection16(deg);
return WeatherCalc.ToCompass16(num);
};

/*
function _formatAirDensity(P, U) {
//(Pressure, Unit)
if (U == 'imperial') {
U = 'lbs/ft3';
} else {
U = 'kg/m3';
}
return (P + ' ' + U);
}

function _formatDistance(D, U) {
//(Distance, Unit)
if (U == 'mi') {
U = 'miles';
} else {
U = 'kilometers';
}
return (D + ' ' + U);
}

function _formatLightningDistance(D, U) {
D = parseFloat(D);
if (D == 0) return '---';
var d = Math.ceil(D),
i = '> ';
if (d > D) {
i = '< ';
}
if (U = 'mi') {
D = _convertDistance(D);
}
return (i + d + ' ' + U)
}

function _formatMeasure(D, U) {
//(Distance, Unit)
if (U == 'imperial') {
U = 'feet';
} else {
U = 'meters';
}
return (D + ' ' + U);
}

function _formatPressure(P, U) {
//(pressure, unit)
if (U == 'inhg') {
U = 'inHg';
} else {
U = 'millibars'
}
return (P + ' ' + U)
}

function _formatTemp(T, U) {
//(temp, unit)
return T + String.fromCharCode(0x00b0) + ' ' + U.toUpperCase();
}
*/

// export as Node module / AMD module / browser variable
if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = WeatherCalc;
else if (typeof define === 'function' && define.amd) define(WeatherCalc);
else window.WeatherCalc = WeatherCalc;

}());``````
6 Likes

@GaryFunk That’s really nice! Thanks for posting that.

I noticed that WeathFlow lists the source for the functions on their page, is that something you could add to the function comments? Also, are you willing to let others use this? If so, under what license conditions?

1 Like

Yes, I could add that source. Many of the functions were pulled from WeatherFlow source which were pulled from those sources. Others were pulled from sources found on government sites and some I created from known math formulas.

As for license I’ll have to figure that out as to who might own what. That being said I should have asked David’s blessing on this.

And as you can see some formulas are not finished and are left over from the RTI driver.

Blessed. We didn’t invent any of those definitions and many of them are just one way to skin the proverbial cat. Although the formulas we use were the result of much research by smarter people than me with years of meteorological experience, I don’t believe anyone owns a copyright on them. So, as far as I know, you are free to use them in your own applications!

3 Likes

Thank you so much. As I didn’t invent any of the methods or formulas, I felt it was best to share what I have gathered. I hope this helps each of you.

By-the-way, there are a few items that don’t work and I am fixing them as I use these in WFArchive. Feel free to download the latest from my website.

2 Likes

FWIW, the dewpoint formula blows up when the RH is 0. I’m curious what the SmartWeather app does at that point. Just not record that data point or set it arbitrarily low?

1 Like

Is zero even possible in humidity? I have never seen it.

In Southern California, several times in the last month we’ve had really really low humidity and AIR has recorded it as 0.

2 Likes

Would either off you please comment on humidity reading zero. Is this as it should be?

1 Like