Sharing a rule to calculate compass directions from degrees

rules
astro
azimuth
Tags: #<Tag:0x00007f0146f7d458> #<Tag:0x00007f0146f7d318> #<Tag:0x00007f0146f7d1d8>

(Kees Van Gelder) #1

azimuthscherm
As far as I know the astro channel only gives the position of the sun in degrees, not in compass directions.
Though I have no problem converting a degree to a compass direction, I might as well have Openhab do that for me.
It is very simple but perhaps other people are helped by it

I made an item called “Zon_Positie”

String Zon_Positie "Positie [%s]" <azimuth>

and in the Sitemap I entered

Text item=Zon_Positie

Rule is then

rule "Zon Positie"
 when
   Item Sun_Azimuth changed
then

if (Sun_Azimuth.state < 11.5 || Sun_Azimuth.state  >= 349)  Zon_Positie.postUpdate("Noord")
 else if (Sun_Azimuth.state >= 11.5 && Sun_Azimuth.state < 34) Zon_Positie.postUpdate("NNO")
 else if (Sun_Azimuth.state >= 34 && Sun_Azimuth.state < 56.5) Zon_Positie.postUpdate("NO")
 else if (Sun_Azimuth.state >= 56.5 && Sun_Azimuth.state < 79) Zon_Positie.postUpdate("ONO")
 else if (Sun_Azimuth.state >= 79 && Sun_Azimuth.state < 101.5) Zon_Positie.postUpdate("Oost")
 else if (Sun_Azimuth.state >= 101.5 && Sun_Azimuth.state < 103) Zon_Positie.postUpdate("OZO")
 else if (Sun_Azimuth.state >= 103 && Sun_Azimuth.state < 147.5) Zon_Positie.postUpdate("ZO")
 else if (Sun_Azimuth.state >= 147.5 && Sun_Azimuth.state < 169) Zon_Positie.postUpdate("ZZO")
 else if (Sun_Azimuth.state >= 169 && Sun_Azimuth.state < 191.5) Zon_Positie.postUpdate("Zuid")
 else if (Sun_Azimuth.state >= 191.5 && Sun_Azimuth.state < 214) Zon_Positie.postUpdate("ZZW")
 else if (Sun_Azimuth.state >= 214 && Sun_Azimuth.state < 236.5) Zon_Positie.postUpdate("ZW")
 else if (Sun_Azimuth.state >= 236.5 && Sun_Azimuth.state < 259) Zon_Positie.postUpdate("WZW")
 else if (Sun_Azimuth.state >= 259 && Sun_Azimuth.state < 281.5) Zon_Positie.postUpdate("West")
 else if (Sun_Azimuth.state >= 281.5 && Sun_Azimuth.state < 304) Zon_Positie.postUpdate("WNW")
 else if (Sun_Azimuth.state >= 304 && Sun_Azimuth.state < 326.5) Zon_Positie.postUpdate("NW")
 else if (Sun_Azimuth.state >= 326.5 && Sun_Azimuth.state < 349) Zon_Positie.postUpdate("NNW")
end

Though the meaning of the Dutch words and abbreviations is not hard to guess, let me just give a little translation:
Noord=North
NNO=NNE (North-North-East)
NO=NE (North-East)
ONO=ENE (East-North-East)
Oost=East
OZO=ESE (EastSouthEast
ZO=SE (South-East)
ZZO=SSE (South-South-East)
Zuid=South
ZZW=SSW (South-South-West)
ZW=SW (SouthWest)
WZW=WSW (West-South-West)
West=West
WNW=WNW (West-North-West
NW=NW (NorthWest)
NNW=NNW (NorthNorthWest)

I have 17 individual icons for this aptly named azimuth.png, azimuth-noord.png, azimuth-nno.png etc, and though they work well, I am not happy with them (just have a look at the picture above) so no use including them.


(Metin) #2

Thank you very much for the code!

I used it to start from, however, for me, the directions were a little too fine-grained, so I reduced them to 8 wind direction names (45° each, and simplified a little). My code also considers the new Units of Measurements. So here’s my code, if someone would like to copy it:

Items

Number:Angle localCurrentWindDirection <wind> { channel="openweathermap:weather-and-forecast:5169a7ba:current#wind-direction" }
String localCurrentWindDirectionText "Wind from [%s]" <wind>

Rule

rule "current wind angle to text"
when
	Item localCurrentWindDirection changed
then
    var Number angle = (localCurrentWindDirection.state as QuantityType<Number>).doubleValue

	if (angle < 22.5)
		localCurrentWindDirectionText.postUpdate("N")
	else if (angle < 22.5 + 45)
		localCurrentWindDirectionText.postUpdate("NE")
	else if (angle < 22.5 + 90)
		localCurrentWindDirectionText.postUpdate("E")
	else if (angle < 22.5 + 135)
		localCurrentWindDirectionText.postUpdate("SE")
	else if (angle < 22.5 + 180)
		localCurrentWindDirectionText.postUpdate("S")
	else if (angle < 22.5 + 225)
		localCurrentWindDirectionText.postUpdate("SW")
	else if (angle < 22.5 + 270)
		localCurrentWindDirectionText.postUpdate("W")
	else if (angle < 22.5 + 315)
		localCurrentWindDirectionText.postUpdate("NW")
	else
		localCurrentWindDirectionText.postUpdate("N")
end

(Vincent Regaud) #3

I use a JS transformation for this:
The advantage is that I can be flexible on what is returned (8 points, 16 points… SW or South West…)

rule

rule "current wind angle to text"
when
	Item localCurrentWindDirection changed
then
    var Number angle = (localCurrentWindDirection.state as QuantityType<Number>).doubleValue
    localCurrentWindDirectionText.postUpdate(transform("JS", "windrose.js", angle.toString)
end

windrose.js

/**
 * Windrose
 *
 * Based loosely on the code by:
 * @author rogeriopvl <http://github.com/rogeriopvl>
 * @license MIT
 *
 * the depth parameter will determine the definition of the windrose
 * depth = 0 : 4 points (N, E, S, W)
 * depth = 1 : 8 points (eg: N, SW, NE...)
 * depth = 2 : 16 points (eg: N, SSW, NNE...)
 * depth = 3 : 32 points (eg: N, NbE, SbW, NNE...)
 * depth = 4 : 64 points (Unused)
 * depth = 5 : 128 points (eg: N¾E, NEbN½N...)
 *
 * the valueReturned parameter will affect the value returned abbreviation or full sentence:
 * valueReturned = symbol : "SE"
 * valueReturned = name: "South East"
 */


(function(i) {

    //ENTER DESIRED DEPTH AND SYMBOL HERE
    var depth = 5; //Enter desired depth here
    var valueReturned = 'symbol'; //Enter returned value here (symbol or name)
    
    var DEPTH_AREA = [ 90, 45, 22.5, 11.25, 5.625, 2.8125 ];
    var COMPASS_POINTS = [
        { symbol: 'N', name: 'North', depth: 0 },
        { symbol: 'N¼E', name: 'North quarter East', depth: 5 },
        { symbol: 'N½E', name: 'North half East', depth: 4 },
        { symbol: 'N¾E', name: 'North three quarters East', depth: 5 },
        { symbol: 'NbE', name: 'North by East', depth: 3 },
        { symbol: 'NbE¼E', name: 'North by East quarter East', depth: 5 },
        { symbol: 'NbE½E', name: 'North by East half East', depth: 4 },
        { symbol: 'NbE¾E', name: 'North by East three quarters East', depth: 5 },
        { symbol: 'NNE', name: 'North North East', depth: 2 },
        { symbol: 'NNE¼E', name: 'North North East quarter East', depth: 5 },
        { symbol: 'NNE½E', name: 'North North East half East', depth: 4 },
        { symbol: 'NNE¾E', name: 'North North East three quarters East', depth: 5 },
        { symbol: 'NEbN', name: 'North East by North', depth: 3 },
        { symbol: 'NEbN¾N', name: 'North East by North three quarters North', depth: 5 },
        { symbol: 'NEbN½N', name: 'North East ny North half North', depth: 4 },
        { symbol: 'NEbN¼N', name: 'North East by North quarter North', depth: 5 },
        { symbol: 'NE', name: 'North East', depth: 1 },
        { symbol: 'NE¼E', name: 'North East quarter East', depth: 5 },
        { symbol: 'NE½E', name: 'North East half East', depth: 4 },
        { symbol: 'NE¾E', name: 'North East three quarters East', depth: 5 },
        { symbol: 'NEbE', name: 'North East by East', depth: 3 },
        { symbol: 'NEbE¼E', name: 'North East by East quarter East', depth: 5 },
        { symbol: 'NEbE½E', name: 'North East by East half East', depth: 4 },
        { symbol: 'NEbE¾E', name: 'North East by East three quarters East', depth: 5 },
        { symbol: 'ENE', name: 'East North East', depth: 2 },
        { symbol: 'ENE¼E', name: 'East North East quarter East', depth: 5 },
        { symbol: 'ENE½E', name: 'East North East half East', depth: 4 },
        { symbol: 'ENE¾E', name: 'East North East three quarter East', depth: 5 },
        { symbol: 'EbN', name: 'East by North', depth: 3 },
        { symbol: 'E¾N', name: 'East three quarters North', depth: 5 },
        { symbol: 'E½N', name: 'East half North', depth: 4 },
        { symbol: 'E¼N', name: 'East quarter North', depth: 5 },
        { symbol: 'E', name: 'East', depth: 0 },
        { symbol: 'E¼S', name: 'East quarter South', depth: 5 },
        { symbol: 'E½S', name: 'East half South', depth: 4 },
        { symbol: 'E¾S', name: 'East three quarters South', depth: 5 },
        { symbol: 'EbS', name: 'East by South', depth: 3 },
        { symbol: 'ESE¾E', name: 'East South East three quarters East', depth: 5 },
        { symbol: 'ESE½E', name: 'East South East half East', depth: 4 },
        { symbol: 'ESE¼E', name: 'East South East quarter East', depth: 5 },
        { symbol: 'ESE', name: 'East South East', depth: 2 },
        { symbol: 'SEbE¾E', name: 'South East by East three quarters East', depth: 5 },
        { symbol: 'SEbE½E', name: 'South East by East half East', depth: 4 },
        { symbol: 'SEbE¼E', name: 'South East by East quarter East', depth: 5 },
        { symbol: 'SEbE', name: 'South East by East', depth: 3 },
        { symbol: 'SE¾E', name: 'South East three quarters East', depth: 5 },
        { symbol: 'SE½E', name: 'South East half East', depth: 4 },
        { symbol: 'SE¼E', name: 'South East quarter East', depth: 5 },
        { symbol: 'SE', name: 'South East', depth: 1 },
        { symbol: 'SE¼S', name: 'South East quarter South', depth: 5 },
        { symbol: 'SE½S', name: 'South East half South', depth: 4 },
        { symbol: 'SE¾S', name: 'South East three quartersSouth', depth: 5 },
        { symbol: 'SEbS', name: 'South East by South', depth: 3 },
        { symbol: 'SSE¾E', name: 'South South East three quarters East', depth: 5 },
        { symbol: 'SSE½E', name: 'South South East half East', depth: 4 },
        { symbol: 'SSE¼E', name: 'South South East quarter East', depth: 5 },
        { symbol: 'SSE', name: 'South South East', depth: 2 },
        { symbol: 'SbE¾E', name: 'South by East three quarters East', depth: 5 },
        { symbol: 'SbE½E', name: 'South by East half East', depth: 4 },
        { symbol: 'SbE¼E', name: 'South by East quarter East', depth: 5 },
        { symbol: 'SbE', name: 'South by East', depth: 3 },
        { symbol: 'S¾E', name: 'South three quarters East', depth: 5 },
        { symbol: 'S½E', name: 'South half East', depth: 4 },
        { symbol: 'S¼E', name: 'South quarter East', depth: 5 },
        { symbol: 'S', name: 'South', depth: 0 },
        { symbol: 'S¼W', name: 'South quarter West', depth: 5 },
        { symbol: 'S½W', name: 'South half West', depth: 4 },
        { symbol: 'S¾W', name: 'South three quarters West', depth: 5 },
        { symbol: 'SbW', name: 'South by West', depth: 3 },
        { symbol: 'SbW¼W', name: 'South by West quarter West', depth: 5 },
        { symbol: 'SbW½W', name: 'South by West half West', depth: 4 },
        { symbol: 'SbW¾W', name: 'South by West three quarters West', depth: 5 },
        { symbol: 'SSW', name: 'South South West', depth: 2 },
        { symbol: 'SSW¼W', name: 'South South West quarter West', depth: 5 },
        { symbol: 'SSW½W', name: 'South South West half West', depth: 4 },
        { symbol: 'SSW¾W', name: 'South South West three quarters West', depth: 5 },
        { symbol: 'SWbS', name: 'South West by South', depth: 3 },
        { symbol: 'SW¾S', name: 'South West three quarters South', depth: 5 },
        { symbol: 'SW½S', name: 'South West half South', depth: 4 },
        { symbol: 'SW¼S', name: 'South West quarter South', depth: 5 },
        { symbol: 'SW', name: 'South West', depth: 1 },
        { symbol: 'SW¼W', name: 'South West quarter West', depth: 5 },
        { symbol: 'SW½W', name: 'South West half West', depth: 4 },
        { symbol: 'SW¾W', name: 'South West three quarters West', depth: 5 },
        { symbol: 'SWbW', name: 'South West by West', depth: 3 },
        { symbol: 'SWbW¼W', name: 'South West by West quarter West', depth: 5 },
        { symbol: 'SWbW½W', name: 'South West by West half West', depth: 4 },
        { symbol: 'SWbW¾W', name: 'South West by West three quarters West', depth: 5 },
        { symbol: 'WSW', name: 'West South West', depth: 2 },
        { symbol: 'WSW¼W', name: 'West South West quarter West', depth: 5 },
        { symbol: 'WSW½W', name: 'West South West half West', depth: 4 },
        { symbol: 'WSW¾W', name: 'West South West three quarters West', depth: 5 },
        { symbol: 'WbS', name: 'West by South', depth: 3 },
        { symbol: 'W¾S', name: 'West three quarters South', depth: 5 },
        { symbol: 'W½S', name: 'West half South', depth: 4 },
        { symbol: 'W¼S', name: 'West quarter South', depth: 5 },
        { symbol: 'W', name: 'West', depth: 0 },
        { symbol: 'W¼N', name: 'West quarter North', depth: 5 },
        { symbol: 'W½N', name: 'West half North', depth: 4 },
        { symbol: 'W¾N', name: 'West three quarters North', depth: 5 },
        { symbol: 'WbN', name: 'West by North', depth: 3 },
        { symbol: 'WNW¾W', name: 'West North West three quarters West', depth: 5 },
        { symbol: 'WNW½W', name: 'West North West half West', depth: 4 },
        { symbol: 'WNW¼W', name: 'West North West quarter West', depth: 5 },
        { symbol: 'WNW', name: 'West North West', depth: 2 },
        { symbol: 'NWbW¾W', name: 'North West by West three quarters West', depth: 5 },
        { symbol: 'NWbW½W', name: 'North West by West half West', depth: 4 },
        { symbol: 'NWbW¼W', name: 'North West by West quarter West', depth: 5 },
        { symbol: 'NWbW', name: 'North West by West', depth: 3 },
        { symbol: 'NW¾W', name: 'North West three quarters West', depth: 5 },
        { symbol: 'NW½W', name: 'North West half West', depth: 4 },
        { symbol: 'NW¼W', name: 'North West quarter West', depth: 5 },
        { symbol: 'NW', name: 'North West', depth: 1 },
        { symbol: 'NW¼N', name: 'North West quarter North', depth: 5 },
        { symbol: 'NW½N', name: 'North West half North', depth: 4 },
        { symbol: 'NW¾N', name: 'North West three quarters North', depth: 5 },
        { symbol: 'NWbN', name: 'North West by North', depth: 3 },
        { symbol: 'NNW¾W', name: 'North North West three quarters West', depth: 5 },
        { symbol: 'NNW½W', name: 'North North West half West', depth: 4 },
        { symbol: 'NNW¼W', name: 'North North West quarter West', depth: 5 },
        { symbol: 'NNW', name: 'North North West', depth: 2 },
        { symbol: 'NbW¾W', name: 'North by West three quarters West', depth: 5 },
        { symbol: 'NbW½W', name: 'North by West half West', depth: 4 },
        { symbol: 'NbW¼W', name: 'North by West quarter West', depth: 5 },
        { symbol: 'NbW', name: 'North by West', depth: 3 },
        { symbol: 'N¾W', name: 'North three quarters West', depth: 5 },
        { symbol: 'N½W', name: 'North half West', depth: 4 },
        { symbol: 'N¼W', name: 'North quarter West', depth: 5 }
    ];

    var degrees = parseInt(i);
    var step = DEPTH_AREA[depth];
    var response = '';

    var compass_points = COMPASS_POINTS.filter(function (pt) {
        return pt.depth <= depth;
    });

    degrees = degrees + (step / 2);
    if (degrees > 360) (degrees = degrees - 360);

    var point = Math.floor(degrees / step);

    response = compass_points[point][valueReturned];

    return response;
}) (input)

(Kees Van Gelder) #4

@metin I am happy you found it of use and thanks for your version of code

@vzorglub That is very useful. I am just not that great in JavaScript, hence my ‘solution’. May try yours if I ever need something similar again


(Anders Alfredsson) #5

I just use a scale transform:

[0..22.5]=N
]22.5..67.5[=NE
[67.5..112.5]=E
]112.5..157.5[=SE
[157.5..202.5]=S
]202.5..247.5[=SW
[247.5..292.5]=W
]292.5..337.5[=NW
[337.5..360]=N

(Jürgen Baginski) #6

@Kees_van_Gelder I know this post is old, but why are you using different steps for the directions? They should all cover exactly 22,5°. You omitted the directions OOZ and WWZ.

Sorry for that, but as a trained navigator I got to pick on that.


(Kees Van Gelder) #7

I don’t think there is much difference in using 22.5 as an angle or as a range, like I do.

The compass scale does not have an OOZ or WWZ, just as it doesnt have an OON or WWN.

It does have an NNNO, ONNO, NONO,OONO, ZOZO, OZZO, ZZZO, ZZZW, WZZW, ZWZW, WWZW, , WWNW and NNNW but I wasnt interested in that amount of detail


(Kees Van Gelder) #8

All roads lead to Rome :slight_smile: Thank you for your addition


(Vincent Regaud) #9

There is still an error in your code:

The list should be:
11.25
33.75
56.25
78.75
101.25
123.75
146.25
168.75
191.25
213.75
236.25
258.75
281.25
303.75
326.25
348.75