Convert Wind Direction (degrees) to Compass Points

I have a FineOffset WH3081 weather station which I monitor with ‘weewx’ on a Linux Mint PC. There’s an extension for weewx that adds MQTT functionality and I’ve used this to also display info on an OpenHAB2 page. Written by Matthew Wall and available HERE.

Anyway, the wind and wind gust directions are returned as angular degrees (0 being North, 90 East etc), so I’ve knocked up a script to turn that input into compass points (NE, SW etc). I thought I’d share it here for those that could take advantage of it. It’s not limited to my situation, it should work on any weather page where this conversion would be handy.

Modify the ‘return’ lines to achieve the output you’d prefer, currently I’m showing both the angular direction and compass point for testing purposes, and seeing what my weather station is returning via weewx mqtt:

(function(i) {
        if(i >= 349 && i <= 11){
                return +i + "° -=- N";
        } else if (i >= 12 && i <= 33) {
                return +i + "° -=- NNE";
        } else if (i >= 34 && i <= 56) {
                return +i + "° -=- NE";
        } else if (i >= 57 && i <= 78) {
                return +i + "° -=- ENE";
        } else if (i >= 79 && i <= 101) {
                return +i + "° -=- E";
        } else if (i >= 102 && i <= 123) {
                return +i + "° -=- ESE";
        } else if (i >= 124 && i <= 146) {
                return +i + "° -=- SE";
        } else if (i >= 147 && i <= 168) {
                return +i + "° -=- SSE";
        } else if (i >= 169 && i <= 191) {
                return +i + "° -=- S";
        } else if (i >= 192 && i <= 213) {
                return +i + "° -=- SSW";
        } else if (i >= 214 && i <= 236) {
                return +i + "° -=- SW";
        } else if (i >= 237 && i <= 258) {
                return +i + "° -=- WSW";
        } else if (i >= 259 && i <= 281) {
                return +i + "° -=- W";
        } else if (i >= 282 && i <= 303) {
                return +i + "° -=- WNW";
        } else if (i >= 304 && i <= 326) {
                return +i + "° -=- NW";
        } else if (i >= 327 && i <= 348) {
                return +i + "° -=- NNW";
        }
})(input)

Item config, the script in my case is named windDir.js in the the CONFIG/transform directory:

String windDir "Wind Direction [JS(windDir.js):%s]"  <wind> (Weather) channel="mqtt:topic:mosquitto:weather:windDir"}
String windGustDir "Wind Gust Direction [JS(windDir.js):%s]" <wind> (Weather) channel="mqtt:topic:mosquitto:weather:windGustDir"}

Snapshot:

Hoping this is helpful to others …

3 Likes

This line will always give false :wink: I’m pretty sure what you want is

if(i >= 349 || i <= 11){
2 Likes

Nit-Pick: You are producing holes in your calculation. I am pretty aware that wind direction degrees will not be issued in scales lower than one degree, but I would suggest you do it like this:

    if(i > 348 && i <= 11){
            return +i + "° -=- N";
    } else if (i > 11 && i <= 33) {
           return +i + "° -=- NNE";
    } else if (i > 33 && i <= 56) {
            return +i + "° -=- NE";
    } else if (i > 56 && i <= 78) {
    ...

That way you ensure you will even catch those numbers correctly.

To bleat even more ;)… You don’t need to define both upper and lower border:

(function(i) {
    val j = (i+11.25) % 360;
         if (j <=  22.5) return +i + "° -=- N";
    else if (j <=  45  ) return +i + "° -=- NNE";
    else if (j <=  67.5) return +i + "° -=- NE";
    else if (j <=  90  ) return +i + "° -=- ENE";
    else if (j <= 112.5) return +i + "° -=- E";
    else if (j <= 135  ) return +i + "° -=- ESE";
    else if (j <= 157.5) return +i + "° -=- SE";
    else if (j <= 180  ) return +i + "° -=- SSE";
    else if (j <= 202.5) return +i + "° -=- S";
    else if (j <= 225  ) return +i + "° -=- SSW";
    else if (j <= 247.5) return +i + "° -=- SW";
    else if (j <= 270  ) return +i + "° -=- WSW";
    else if (j <= 292.5) return +i + "° -=- W";
    else if (j <= 315  ) return +i + "° -=- WNW";
    else if (j <= 337.5) return +i + "° -=- NW";
    else                 return +i + "° -=- NNW";

})(input)

Sorry, but the old navigator has to step in.
It might be that I do not understand the used code but IMHO the used steps are wrong!

N for North would be assigned to courses from above 348,75 over 360 (which is 0 ) to 11,25
NNE from above 11,25 to 33,75 …
The steps are all 22,5 ° wide.

Jep, but you missed the tricky part :wink: I added 11.25 so north is now 0° to 22.5° (val j)

1 Like

:hugs: So I was NOT understanding the code.

@Udo_Hartmann and @zobelhelas you’re indeed right, I do like the look of this solution best though. Thanks guys.

EDIT: it doesn’t work as expected though.

My amended version using the actual compass points even though my readings are integers, this still holds true. Yes I know if we get down to the final condition it could simply be an ‘else’ statement, and that all of the conditions could be one liners, but to me it’s more readable in this form.

(function(i) {
        if(i >= 348.75 || i < 11.25){
                return +i + ". -=- N";
        } else if (i >= 11.25 && i < 33.75) {
                return +i + ". -=- NNE";
        } else if (i >= 33.75 && i < 56.25) {
                return +i + ". -=- NE";
        } else if (i >= 56.25 && i < 78.75) {
                return +i + ". -=- ENE";
        } else if (i >= 78.25 && i < 101.25) {
                return +i + ". -=- E";
        } else if (i >= 101.25 && i < 123.75) {
                return +i + ". -=- ESE";
        } else if (i >= 123.75 && i < 146.25) {
                return +i + ". -=- SE";
        } else if (i >= 146.25 && i < 168.75) {
                return +i + ". -=- SSE";
        } else if (i >= 168.75 && i < 191.25) {
                return +i + ". -=- S";
        } else if (i >= 191.25 && i < 213.75) {
                return +i + ". -=- SSW";
        } else if (i >= 213.75 && i < 236.25) {
                return +i + ". -=- SW";
        } else if (i >= 236.25 && i < 258.75) {
                return +i + ". -=- WSW";
        } else if (i >= 258.75 && i < 281.25) {
                return +i + ". -=- W";
        } else if (i >= 281.25 && i < 303.75) {
                return +i + ". -=- WNW";
        } else if (i >= 303.75 && i < 326.25) {
                return +i + ". -=- NW";
        } else if (i >= 326.25 && i < 348.75) {
                return +i + ". -=- NNW";
        }
})(input)

Hi all,

Just a slight pointer to the Scale Transformation which does the math for you.

Have fun.

2 Likes

Brilliant, thanks for that @cweitkamp. I was looking for a way to do that with a normal transform, but as far as I understood it, it only allows a single value either side of the =. Didn’t know about the Scale Transformation, thanks for bringing it to my attention. I’ll stick to my script for now though so I can return both the angular direction and the compass point together. But I’ll definitely use the scale transform once I’m happy with the values my weather station provides.

I think the second line should be

var j = (…

instead of

val j = (…

at least that way it works for me :slight_smile:

My guess is you do not know the difference between a val (value) and a var (variable).

1 Like

For shure I don’t know the to much about the JS Implementation within OH rules, but my installation complains about val but not about var.
var: object; val: method

Perhaps you could show us the error message.

Happy to find this. However, having a problem with the item definitions…

I am not sure how this code works with item definitions, but it breaks my sitemap (where only frame names are shown, no items). If I remove it, the value is shown as null.

I’ve tried with and without the padding spaces, confirmed javascript transformation, confirmed string item type… what am I missing?

Oh, maybe I need to wait for an item update? It should have come through by now…

Take the <----> and <> parts out and replace with spaces, they’re tabs, that was me copying from my editor which was set to show tabs which then became part of that copy.

EDIT: I’ve now cleaned up that copy problem in the original post.

cool - will try, thanks!

Strange, it doesn’t seem to be returning a valid result:

Mqtt_WeatherStation_WindDir changed from NULL to 1969-12-31T19:04:22.000-0500

Will have to look at later, but if you have any ideas…