Own barometer eg."forecast"

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

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

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) :slight_smile:

interesting source might be this:
http://www.truganinaweather.com/projects/zambretti-forecaster-project.htm

// barometer forecast
rule "Weather: barometric forecast"
when
    //Item House_Pressure_Sealevel received update or
    //Item WS_LastUpdate changed
    Time cron "0 0 * * * ?"
then
    //val prev_time = hPressure_lastchange.state
    val ZonedDateTime zdt = ZonedDateTime.now()
    val ZonedDateTime today = zdt.toLocalDate().atStartOfDay(zdt.getOffset())

    val prev_mbar = (hPressure_Prev.state as Number).floatValue
    val mbar      = (House_Pressure_Sealevel.state as Number).floatValue
    val diff      = mbar - prev_mbar
    val prev_diff = (hPressure_Diff.state as Number).floatValue
    val diffM     = prev_diff + diff
    val trendSum  = hPressure_Trend.sumSince(today)

    hPressure_Diff.sendCommand(diff)
    hPressure_Prev.sendCommand(mbar)
    postUpdate(hPressure_lastchange, now.toInstant.toString)
    postUpdate(hPressure_TrendSum,trendSum)

    var cond = 2
    // 1 = High
    // 2 = Normal
    // 3 = Low

    switch mbar {
        case mbar >  1022.689                       : cond = 1
        case mbar <= 1022.689 && mbar >= 1009.144   : cond = 2
        case mbar <  1009.144                       : cond = 3
    }

    var speed = 1
    // 1 = rising/steady
    // 2 = slow fall
    // 3 = rapid fall

    switch diff {
        case diff >  0              : speed = 1
        case diff >  -1 && diff < 0 : speed = 2
        case diff <= -1             : speed = 3
    }

    var Number trend = 0
    //  1 up
    //  0 steady
    // -1 down

    switch diffM {
        case diffM  > 0 : trend = 1
        case diffM  < 0 : trend = -1
        default         : trend = 0
    }
    postUpdate(hPressure_Trend,trend)

    var String conditions = "Unknown"

    if(cond == 1){          // high pressure
        if(speed == 1)  conditions = "Continue Fair Weather"
        if(speed == 2)  conditions = "Fair Weather"
        if(speed == 3)  conditions = "Cloudy and Warmer"
    }else if (cond == 2){   // normal pressure
        if(speed == 1)  conditions = "Continue Current Weather"
        if(speed == 2)  conditions = "Little change of the Weather"
        if(speed == 3){
            if(Season.state == "WINTER"){
                        conditions = "Snow"
            }else{
                        conditions = "Rain"
            }
        }  
    }else{                  // low pressure
        if(speed == 1)  conditions = "Clearing sky, Cooler Weather"
        if(speed == 2)  conditions = "Rain"
        if(speed == 3)  conditions = "Storm"
    }

/*
    logInfo("y",cond.toString)
    logInfo("y",speed.toString)
    
    logInfo("x",conditions)
    logInfo("x",diffM.toString)
    logInfo("x",diff.toString)
    logInfo("x",trendSum.toString)
*/

    postUpdate(hBarometric_Forecast, conditions)

/*
When the air is dry, cool, and pleasant, the barometer reading rises.
In general, a rising barometer means improving weather.
In general, a falling barometer means worsening weather.
When atmospheric pressure drops suddenly, this usually indicates that a storm is on its way.
When atmospheric pressure remains steady, there will likely be no immediate change in the weather.


High pressure over 1022.689
    Rising or steady pressure means continued fair weather.
    Slowly falling pressure means fair weather.
    Rapidly falling pressure means cloudy and warmer conditions.

Normal pressure 1022.689–1009.144
    Rising or steady pressure means present conditions will continue.
    Slowly falling pressure means little change in the weather.
    Rapidly falling pressure means that rain is likely, or snow if it is cold enough.

Low Pressure under 1009.144 mb
    Rising or steady pressure indicates clearing and cooler weather.
    Slowly falling pressure indicates rain.
    Rapidly falling pressure indicates a storm is coming.
*/

end

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

You should take à look at Sagercaster binding

1 Like

wow thanks, looks promising! :slight_smile:

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

credits: Weather Station – Raspberry Pi and Stuff

3 Likes

Thanks for sharing your code. I’ll test it with my I2C air pressure sensor and report back.

Please note that one of the input parameters is the season (vMonth). Therefore, the code must be modified if used in the Southern Hemisphere.

This could be a good candidate to be implemented as an automation module.

Zambretti at work:

grafik

Zambretti Number 1 (ZN1) is defined in relation to the Zambretti numbers from the DSL script (ZND):

  • ZN1 1001-1009: falling conditions ZND 1-9
  • ZN1 1010-1019: steady conditions ZND 1-10
  • ZN1 1020-1032: rising conditions ZND 1-13

Does the Zambretti forecaster work? Well, I’m not sure …

BTW, see Zambretti Forecaster - Wikipedia for the real device.