# Sharing a rule to calculate compass directions from degrees

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.

7 Likes

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
``````

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>
*
* 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)
``````
1 Like

@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

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
``````
3 Likes

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

1 Like

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

1 Like

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

2 Likes

Using metins code above I can transalte my weather station degrees to compass points.
However I’ve tried to use the same code (I’m not that good at coding) to change a Weather condition number value to a text description
eg
rule “current conditions wt1 to text”
when
Item W_Type1 changed
then
var Number wt1 = (W_Type1.state as QuantityType).doubleValue

``````   if (wt=0)
W_Type1_Text.postupdate ("Clear Night")
else if....
``````

Goes on for 30 codes
Item works as I did that before I did the rule
What I get when I load the rule is “variable wt1 not used in rules” therefore ignoring - loads but doesnt work
Since not used val I havent been able figure it out as that is what a lot of posts suggest

In the if part you have typo in the variable name ( used wt Instead of wt1).
Have a look into examples using “select case”, the way the handling of 30 cases is better.

var declares a variable, which can change
val declares a value, which is set once.

so var is correct - I mistyped it does say wt1 not wt - I’m at work and cant directly access my code on this computer

Since you are assigning wt1 only once a value could also be
The error shown pointed to such a mistake.
When posting code again please use code fences, that way to code becomes readable!

Why not use a Scale transform? This could have been used for compass directions too.

Thank you - that’s what I did in the end - works well - and simpler

1 Like

I didnt know though one could supply a range in a map…so definitly learned something

It’s not a MAP transform, it’s a SCALE transform… A bit different
The syntax is very similar but the files have `.scale` extension

1 Like

Thanks, learned again something new

I use it for wind scale beaufort:
Mine is in mph to text so you’d have to change the values for km/h or m/s

``````[0..1[=Calm
[1..4[=Light air
[4..8[=Light breeze
[8..13[=Gentle breeze
[13..19[=Moderate breeze
[19..25[=Fresh breeze
[25..32[]=Strong breeze
[32..39[=High wind
[39..47[=Gale
[47..55[=Severe gale
[55..64[=Storm
[64..73[=Violent storm
[73..96[=Hurricane CAT 1
[96..111[=Hurricane CAT 2
[111..130[=Hurricane CAT 3
[130..157[=Hurricane CAT 4
[157..]=Hurricane CAT 5
``````
1 Like

good to know. May start to use that more often. Thank you