So I was wondering if anybody went down the road of creating a ruleset for virtual barometer and it does not look like so … at least on this forum.
I’ve had some spare time and many measurements from my home-weather-sensors-house-garden-station … which need some use
Any help,ideas,thoughts are appreciated as this code is WORK IN PROGRESS and as it is from today, it’s messy and need indeed some love
from couple of webpages i’ve gathered how to read barometer, but i havent found anything about time-wise eg. what is slow/fast drop etc. so for now, i’m using hourly measurements to determine speed of change, trending etc.
not everything is used and not everything is right, but we’ll get there.
I think biggest question for now is how big have to be change in which timeperiod to be able to say it’s falling rapidly or steadily and then display proper informations.
I can combine these with many other values I already have, like dew point, cloudiness, temperature, humidity, windspeed, winddirection, trends … but as I’m not meteorologist, not sure what with what to combine properly.
(and yes I know there is openweather, but i want use data on exact location which can be very different from forecast miles away)
Forecasting is more involved than just monitoring the barmoetric pressure. You also have to take into account wind direction and elevation plays a role too. Also, manuals I’ve read for analog barometers say that checking too often may lead to a misleading impression on what’s going on. A couple times a day is about all you need to check because you mainly care about the long term trend. There are atmospheric tides and other conditions that can cause lots of variation over a short period of time.
From what I can find and what I remember, the definition of “rapidly” is going to depend on correlating observations for your specific area. So if you see the pressure fall over a 24 hour period and a couple days later you have a storm, you’ve found at least one instance of “rapid”.
I live in British Columbia, Canada. Two weekends ago we had historic rainfall that caused massive flooding throughout the province. It was attributed to an “atmospheric river”, which I’d never heard of, but is apparently a thing for meteorologists.
It rained non-stop through a Saturday and Sunday, rained even harder on the Monday morning, and then it just stopped, and the afternoon was bright and sunny. Apparently it might be back later this week.
This is less than six months after the “heat dome” that caused massive drought in Western North America in the summer. So went from having no rain for weeks on end to an insane amount of rain in a handful of days.
It really reinforces the relationship between weather patterns and chaos theory.
this is about barometric forecast not super fancy overcomplicated 100% accurate forecast… barometers are with us for quite a while and I like that idea.
So in the meanwhile I’ve adapted Zambretti Forecaster into DSL
// barometer forecast
rule "Weather: Zambretti Forecaster"
when
Time cron "0 */30 * * * ?"
then
val p0 = (House_Pressure_Sealevel.state as Number).floatValue
val p1 = House_Pressure_Sealevel.averageSince(now.minusMinutes(30))
val p2 = House_Pressure_Sealevel.averageSince(now.minusMinutes(60))
val p3 = House_Pressure_Sealevel.averageSince(now.minusMinutes(90))
val p4 = House_Pressure_Sealevel.averageSince(now.minusMinutes(120))
val p5 = House_Pressure_Sealevel.averageSince(now.minusMinutes(150))
val p6 = House_Pressure_Sealevel.averageSince(now.minusMinutes(180))
val p7 = House_Pressure_Sealevel.averageSince(now.minusMinutes(210))
val p8 = House_Pressure_Sealevel.averageSince(now.minusMinutes(240))
val p9 = House_Pressure_Sealevel.averageSince(now.minusMinutes(270))
val p10 = House_Pressure_Sealevel.averageSince(now.minusMinutes(300))
val p11 = House_Pressure_Sealevel.averageSince(now.minusMinutes(330))
val p12 = House_Pressure_Sealevel.averageSince(now.minusMinutes(360))
// calculate single differencies and normalize them to a change in pressure over 1h
val pd1 = (p0 - p1) * 2
val pd2 = (p0 - p2)
val pd3 = (p0 - p3) / 1.5
val pd4 = (p0 - p4) / 2
val pd5 = (p0 - p5) / 2.5
val pd6 = (p0 - p6) / 3
val pd7 = (p0 - p7) / 3.5
val pd8 = (p0 - p8) / 4
val pd9 = (p0 - p9) / 4.5
val pd10 = (p0 - p10) / 5
val pd11 = (p0 - p11) / 5.5
val pd12 = (p0 - p12) / 6
// calculate average
val pdiff = (pd1 + pd2 + pd3 + pd4 + pd5 + pd6 + pd7 + pd8 + pd9 + pd10 + pd11 + pd12) / 12
val curr = p0
var String forecast = "Unknown"
// calculate trend
var Number trend = 0
switch pdiff {
case pdiff < -0.25 : trend = -1
case pdiff > 0.25 : trend = 1
default : trend = 0
}
if(trend == -1) // failing conditions
{
var zambretti = 0.0009746 * curr * curr - 2.1068 * curr + 1138.7019
if(vMonth.state < 4 || vMonth.state > 9) zambretti = zambretti + 1
zambretti = Math.round(zambretti)
switch zambretti {
case zambretti == 1: forecast = "Settled Fine"
case zambretti == 2: forecast = "Fine Weather"
case zambretti == 3: forecast = "Fine Becoming Less Settled"
case zambretti == 4: forecast = "Fairly Fine Showers Later"
case zambretti == 5: forecast = "Showery Becoming unsettled"
case zambretti == 6: forecast = "Unsettled, Rain later"
case zambretti == 7: forecast = "Rain at times, worse later"
case zambretti == 8: forecast = "Rain at times, becoming very unsettled"
case zambretti == 9: forecast = "Very Unsettled, Rain"
}
}
else if(trend == 0) // steady conditions
{
var zambretti = 138.24 - 0.133 * curr
zambretti = Math.round(zambretti)
switch zambretti {
case zambretti == 1: forecast = "Settled Fine"
case zambretti == 2: forecast = "Fine Weather"
case zambretti == 3: forecast = "Fine, Possibly showers"
case zambretti == 4: forecast = "Fairly Fine, Showers likely"
case zambretti == 5: forecast = "Showery Bright Intervals"
case zambretti == 6: forecast = "Changeable some rain"
case zambretti == 7: forecast = "Unsettled, rain at times"
case zambretti == 8: forecast = "Rain at Frequent Intervals"
case zambretti == 9: forecast = "Very Unsettled, Rain"
case zambretti == 10: forecast = "Stormy, much rain"
}
}
else // rising conditions
{
var zambretti = 142.57 - 0.1376 * curr
if(vMonth.state < 4 || vMonth.state > 9) zambretti = zambretti + 1
zambretti = Math.round(zambretti)
switch zambretti {
case zambretti == 1: forecast = "Settled Fine"
case zambretti == 2: forecast = "Fine Weather"
case zambretti == 3: forecast = "Becoming Fine"
case zambretti == 4: forecast = "Fairly Fine, Improving"
case zambretti == 5: forecast = "Fairly Fine, Possibly showers, early"
case zambretti == 6: forecast = "Showery Early, Improving"
case zambretti == 7: forecast = "Changeable, Improving"
case zambretti == 8: forecast = "Unsettled, Probably Improving"
case zambretti == 9: forecast = "Very Unsettled, Rain"
case zambretti == 10: forecast = "Unsettled, short fine Intervals"
case zambretti == 11: forecast = "Very Unsettled, Finer at times"
case zambretti == 12: forecast = "Stormy, possibly improving"
case zambretti == 13: forecast = "Stormy, much rain"
}
}
postUpdate(hBarometric_Zambretti, forecast)
end
I think Zambretti tried to be more “precise” at time of invention than regular barometers were, not necessarily better or worse. I think algorithm is being proven by years and you can research about it if wanted.
in the meanwhile I’ve adapted my code to provide both Zabretti and “regular” barometer as well.
In comparison between them and with comparison with Sagercaster - it looks both works pretty much same “predicting” very similar results. Zambretti maybe slighly better. So on my end, this is what I wanted.
Old school “own” at my location prediction.
Feel free to adjust code, suggest changes etc.
edit: updated code, some cleanup. wind adjust and code definition for optional map file to translate it better
// barometer forecast
rule "Weather: Barometric & Zambretti Forecaster"
when
Time cron "0 0 9 * * ?" or // 9h
Time cron "0 0 15 * * ?" or // 15h
Time cron "0 0 21 * * ?" or // 21h
System started
then
val p0 = (House_Pressure_Sealevel.state as Number).floatValue
val p1 = House_Pressure_Sealevel.averageSince(now.minusMinutes(30))
val p2 = House_Pressure_Sealevel.averageSince(now.minusMinutes(60))
val p3 = House_Pressure_Sealevel.averageSince(now.minusMinutes(90))
val p4 = House_Pressure_Sealevel.averageSince(now.minusMinutes(120))
val p5 = House_Pressure_Sealevel.averageSince(now.minusMinutes(150))
val p6 = House_Pressure_Sealevel.averageSince(now.minusMinutes(180))
val p7 = House_Pressure_Sealevel.averageSince(now.minusMinutes(210))
val p8 = House_Pressure_Sealevel.averageSince(now.minusMinutes(240))
val p9 = House_Pressure_Sealevel.averageSince(now.minusMinutes(270))
val p10 = House_Pressure_Sealevel.averageSince(now.minusMinutes(300))
val p11 = House_Pressure_Sealevel.averageSince(now.minusMinutes(330))
val p12 = House_Pressure_Sealevel.averageSince(now.minusMinutes(360))
// calculate single differencies and normalize them to a change in pressure over 1h
val pd1 = (p0 - p1) * 2
val pd2 = (p0 - p2)
val pd3 = (p0 - p3) / 1.5
val pd4 = (p0 - p4) / 2
val pd5 = (p0 - p5) / 2.5
val pd6 = (p0 - p6) / 3
val pd7 = (p0 - p7) / 3.5
val pd8 = (p0 - p8) / 4
val pd9 = (p0 - p9) / 4.5
val pd10 = (p0 - p10) / 5
val pd11 = (p0 - p11) / 5.5
val pd12 = (p0 - p12) / 6
// calculate average
val pdiff = (pd1 + pd2 + pd3 + pd4 + pd5 + pd6 + pd7 + pd8 + pd9 + pd10 + pd11 + pd12) / 12
// temperature
val Number temp = (WS_Temperature.state as Number).floatValue
// barometer
// high/normal/low pressure
var Number cond = 2
switch p0 {
case p0 > 1022.689 : cond = 1 // high pressure
case p0 < 1009.144 : cond = 3 // low pressure
default : cond = 2 // normal pressure
}
var Number speed = 1
// rapid/slow or steady
switch pdiff {
case pdiff > 0.75 : speed = 3
case pdiff > 0.42 : speed = 2
case pdiff > 0.25 : speed = 1
case pdiff < -0.75 : speed = 3
case pdiff < -0.42 : speed = 2
case pdiff < -0.25 : speed = 1
}
var String bf = "Unknown"
// high pressure
if(cond == 1){
if(speed == 1) bf = "Continue Fair Weather"
if(speed == 2) bf = "Fair Weather"
if(speed == 3) bf = "Cloudy and Warmer"
}
// normal pressure
else if (cond == 2){
if(speed == 1) bf = "Continue Current Weather"
if(speed == 2) bf = "Little change of the Weather"
if(speed == 3){
if(temp < 0.5) bf = "Snow"
else bf = "Rain"
}
}
// low pressure
else{
if(speed == 1) bf = "Clearing sky, Cooler Weather"
if(speed == 2){
if(temp < 0.5) bf = "Snow"
else bf = "Rain"
}
if(speed == 3) bf = "Storm"
}
postUpdate(hBarometric_Forecast, bf)
//
// zambretti
// calculate trend
var Number trend = 0
switch pdiff {
case pdiff < -0.25 : trend = -1
case pdiff > 0.25 : trend = 1
default : trend = 0
}
var Number curr = p0
var String zf = ""
// failing conditions
if(trend < 0)
{
var zmb = Math.round(0.0009746 * curr * curr - 2.1068 * curr + 1138.7019)
if(vMonth.state < 4 || vMonth.state > 9) zmb = zmb - 1
switch (zmb.intValue) {
case 1: zf = "A"
case 2: zf = "B"
case 3: zf = "D"
case 4: zf = "H"
case 5: zf = "O"
case 6: zf = "R"
case 7: zf = "U"
case 8: zf = "V"
case 9: zf = "X"
default: zf = "Unknown/Falling"
}
}
// rising conditions
else if(trend > 0)
{
var zmb = Math.round(142.57 - 0.1376 * curr)
if(vMonth.state < 4 || vMonth.state > 9) zmb = zmb + 1
switch (zmb.intValue) {
case 1: zf = "A"
case 2: zf = "B"
case 3: zf = "C"
case 4: zf = "F"
case 5: zf = "G"
case 6: zf = "I"
case 7: zf = "J"
case 8: zf = "L"
case 9: zf = "M"
case 10: zf = "Q"
case 11: zf = "T"
case 12: zf = "Y"
case 13: zf = "Z"
default: zf = "Unknown/Rising"
}
}
// steady conditions
else
{
var zmb = Math.round(138.24 - 0.133 * curr)
switch (zmb.intValue) {
case 1: zf = "A"
case 2: zf = "B"
case 3: zf = "E"
case 4: zf = "K"
case 5: zf = "N"
case 6: zf = "P"
case 7: zf = "S"
case 8: zf = "W"
case 9: zf = "X"
case 10: zf = "Z"
default: zf = "Unknown/Steady"
}
}
var String out = "-"
switch (zf) {
case "A" : out = "Settled fine weather" // Sun
case "B" : out = "Fine weather" // Sun
case "C" : out = "Becoming fine" // Sun
case "D" : out = "Fine, Becoming less settled" // Sun & Clouds
case "E" : out = "Fine, Possibly showers" // Sun & Clouds
case "F" : out = "Fairly fine, Improving" // Sun
case "G" : out = "Fairly fine, Possibly showers early" // Sun & Clouds
case "H" : out = "Fairly fine, Showers later" // Sun & Clouds
case "I" : out = "Showery early, Improving" // Sun & Clouds
case "J" : out = "Changeable, Improving" // Sun & Clouds
case "K" : out = "Fairly Fine, Showers likely" // Sun & Clouds
case "L" : out = "Rather Unsettled clearing later" // Sun & Clouds
case "M" : out = "Unsettled, Probably improving" // Sun & Clouds
case "N" : out = "Showery bright intervals" // Sun & Clouds
case "O" : out = "Showery becoming unsettled" // Sun & Clouds
case "P" : out = "Changeable some rain" // Sun & Clouds
case "Q" : out = "Unsettled, Short fine intervals" // Sun & Clouds
case "R" : out = "Unsettled, Rain later" // Rain
case "S" : out = "Unsettled, Rain at times" // Rain
case "T" : out = "Very Unsettled, Finer at times" // Sun & Clouds
case "U" : out = "Rain at times, Worse later" // Rain
case "V" : out = "Rain at times, Becoming very unsettled" // Rain
case "W" : out = "Rain at Frequent Intervals" // Rain
case "X" : out = "Very unsettled, Rain" // Rain
case "Y" : out = "Stormy, Possibly improving" // Storm
case "Z" : out = "Stormy, Much rain" // Storm
default : out = "Uknown"
}
postUpdate(hBarometric_Trend,trend)
postUpdate(hBarometric_ZambrettiCode,zf)
postUpdate(hBarometric_Zambretti, out)
postUpdate(hBarometric_Time,now.toInstant.toString)
end
hi,
latest code is using these outputs
first one is “regular” barometer - just for some research/comparison
second one is populated directly by the rule as string
third is populated by zambretti letter so you can create map file as you want.
//A = Settled fine weather
//B = Fine weather
//C = Becoming fine
//D = Fine, Becoming less settled
//E = Fine, Possibly showers
//F = Fairly fine, Improving
//G = Fairly fine, Possibly showers early
//H = Fairly fine, Showers later
//I = Showery early, Improving
//J = Changeable, Improving
//K = Fairly Fine, Showers likely
//L = Rather Unsettled clearing later
//M = Unsettled, Probably improving
//N = Showery bright intervals
//O = Showery becoming unsettled
//P = Changeable some rain
//Q = Unsettled, Short fine intervals
//R = Unsettled, Rain later
//S = Unsettled, Rain at times
//T = Very Unsettled, Finer at times
//U = Rain at times, Worse later
//V = Rain at times, Becoming very unsettled
//W = Rain at Frequent Intervals
//X = Very unsettled, Rain
//Y = Stormy, Possibly improving
//Z = Stormy, Much rain
Unknown = Out of scale
NULL = Unknown
A = Sun
B = Sun
C = Sun
D = Sun & Clouds
E = Sun & Clouds
F = Sun
G = Sun & Clouds
H = Sun & Clouds
I = Sun & Clouds
J = Sun & Clouds
K = Sun & Clouds
L = Sun & Clouds
M = Sun & Clouds
N = Sun & Clouds
O = Sun & Clouds
P = Sun & Clouds
Q = Sun & Clouds
R = Rain
S = Rain
T = Sun & Clouds
U = Rain
V = Rain
W = Rain
X = Rain
Y = Storm
Z = Storm
-1 = Falling
1 = Rising
0 = Steady
as a next step I want to display some icons based on the letters
I did add - = Unknown to the ‘.map’ file as I was getting some transformation errors initially, but now its updated with data the mapping is working.
I also didn’t have any default ‘persistence’ set as I use InfluxDB to store temp/pressure data, so I’ve set that to RRD4j and its picked up the previous pressure values.
I see you have changed the rule a bit and added a local temperature as well rather than a season for rain/snow. That should be a lot more accurate.
I’ll keep an eye on the output and see how accurate the predictions are.
yes, I’ve changed it because now it’s Autumn and snowing anyway, so … I’m trying to guess if snow is accurate that way.
I’ve removed adjustment for wind directions, as it is already averaged in our version of the zambretti number.
As far as i can tell, it’s pretty accurate.
I’m now just trying to set proper times to calculate, as it seems best result at 9am and in the afternoon. But might be ok-ish ever 2hours or so as well.
btw I’m using influx as well, so should be working…
I’m in the South of the UK and we don’t often get snow, so temperature is definitely more important in trying to predict it.
I am getting a failure now with vMonth in the rule. (The name 'vMonth' cannot be resolved to an item or type; line 109, column 12, length 6 ). Where are you defining that items state?