Wind Gauge with Compass

This is a dashboard widget for displaying wind speed and direction in one gauge.

The gauge takes three inputs from msg.payload:

  1. speed (number)
  2. speed_unit (string) - Any string you want displayed after the speed, e.g. MPH, KMH, KTS, etc
  3. degrees (0-360 to for compass direction)

An example input node is included. You can replace it with your own data source (e.g. wunderground PWS)

Tested on Safari & Chrome (sorry, I have no access to IE or Edge).

[{"id":"409af0a5.b6e3e8","type":"inject","z":"c03635b9.79bbc","name":"","topic":"","payload":"","payloadType":"date","repeat":"2","crontab":"","once":true,"x":310,"y":180,"wires":[["d12411f0.075428"]]},{"id":"a3654026.abf898","type":"ui_template","z":"c03635b9.79bbc","group":"64704468.613964","name":"Wind","order":1,"width":"4","height":"4","format":"<!--\npass msg.payload.degrees, msg.payload.speed, msg.payload.speed_unit\n-->\n<script>\n    // Watch the incoming message and convert the degrees to a human readable compass direction\n    (function(scope){\n        scope.$watch('msg', function(msg) {\n            if(typeof(msg) === \"object\"){\n                // Convert the degrees to cardinal directions\n                var deg = msg.payload.degrees;\n                var dirs = [\"N\",\"NNE\",\"NE\",\"ENE\",\"E\",\"ESE\",\"SE\",\"SSE\",\"S\",\"SSW\",\"SW\",\"WSW\",\"W\",\"WNW\",\"NW\",\"NNW\",\"N\"];\n                var idx = Math.round(deg*(dirs.length-1)/360);\n                scope.direction = dirs[idx];\n                \n                \n                // Keep track of the highest speed value, giving it 40 as a rough starting point.\n                // Works okay for MPH and KTS, but KMH will show purple at a lower speed than the rest\n                scope.max_val = (msg.payload.speed > scope.max_val ? msg.payload.speed : 40);\n                \n                scope.p_speed = msg.payload.speed;\n                scope.p_max_val = scope.max_val;\n                var low_colors = [\n                    '#FFFFFF', // white\n                    '#d6f7ff', // light blue\n                    '#85ffd2', // blue green\n                    '#61ff6e' // green 10mph\n                    ];\n                var high_colors = [\n                    '#61ff6e', // green 10mph\n                    '#d5ff61', // green yellow\n                    '#fffc61', // yellow\n                    '#ffe561', // yellow orange 20mph\n                    '#ffcd61', // orange\n                    '#ffad61', // orange red\n                    '#ff7661', // red\n                    '#ff61dd', // red purple\n                    '#e261ff' // purple\n                ];\n                \n                if(msg.payload.speed <= 10){\n                    scope.color = low_colors[Math.round(msg.payload.speed*(low_colors.length-1)/10)];\n                }else{\n                    scope.color = high_colors[Math.round(msg.payload.speed*(high_colors.length-1) / scope.max_val)];\n                }\n                \n                //$(\".compass_container\").css(\"background-color\",scope.color);\n            }\n    \t});\n    })(scope);\n    \n    // Hacks to improve the layout and make it scale\n    $(document).ready(function(){\n        setTimeout(function () {\n            // Remove the auto scrolling from the parent node\n            $(\".compass_container\").parent().css(\"overflow\",\"hidden\");\n        \n            // Adjust the color to match the theme base color by looking up the toolbar header background color;\n            $(\".compass_container .triangle\").css(\"border-bottom-color\",$(\"md-toolbar\").css(\"background-color\"));\n        \n            // Scale the compass into the box that it's being rendered in\n            // This CSS hack helps make sure the line & font size scales appropriately\n            // Based on the node's grid size\n            $(\".compass_container\").each(function(k,v){\n                var scaleWidth = $(v).parent().width() / $(v).width();\n                var scaleHeight = $(v).parent().height() / $(v).height();\n        \n                var translateX = ($(v).width() - $(v).parent().width()) / 2;\n                var translateY = ($(v).height() - $(v).parent().height()) / 2;\n        \n                $(v).css(\"transform\",\"translate(-\"+translateX+\"px,-\"+translateY+\"px) scale(\"+scaleWidth+\",\"+scaleHeight+\") \");\n            });\n            \n            $(\".compass_container\").css(\"display\",\"block\"); // Unhide it now that it's resized\n        }, 1000);\n    });\n</script>\n<style>\n     @import url(,400,500,600);\n     \n     .compass_container{\n        transition: 1s ease-in-out;\n        position: relative;\n        display: none;\n        width: 500px;\n        height: 500px;\n        border-radius: 100%;\n        font-family: 'Dosis';\n        font-size: 80px;\n        box-shadow: inset 0px 0px 0px 30px #777; \n        background-color: {{color}};\n     }\n     \n     .compass_container .compass_header{\n        font-weight: bold;\n        position: absolute;\n        text-align: center;\n        width: 100%;\n        font-size: 75%;\n        top: -15px\n     }\n     .compass_container .text_container{\n        height: 100%;\n        width: 100%;\n        padding: 0px;\n        display: block;\n        border-radius: 100%;\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        align-items: center;\n     }\n     \n     .compass_container .arrow{\n        transition: 1s ease-in-out;\n        width: 100%;\n        height: 100%;\n        display: block;\n        position: absolute;\n        top: 0;\n     }\n     \n     .compass_container .arrow .triangle{\n        width: 0;\n\t\theight: 0;\n\t\tborder-left: 45px solid transparent;\n\t\tborder-right: 45px solid transparent;\n\t\tborder-bottom: 90px solid black;\n\t\tposition: absolute;\n\t\ttop: -15px;\n\t\tleft: 50%;\n\t\tmargin-left: -45px;\n\t\tz-index: 99;\n     }\n</style>\n\n<div class=\"compass_container\" style=\"\">\n    <div class=\"compass_header\">N</div>\n  \n    <div class=\"nr-dashboard-text text_container\">\n    \n        <div class=\"direction\" style=\"font-size: 120%\">{{direction}}</div>\n        <div style=\"flex-direction: row; font-weight: bold;\">\n            <span style=\"font-size: 100%\">{{msg.payload.speed}}</span>\n            <span style=\"font-size: 75%\">{{msg.payload.speed_unit}}</span>\n        </div>\n    </div>\n    <div class=\"arrow\" style=\"transform: rotate({{msg.payload.degrees}}deg);\">\n      <div class=\"triangle\"></div>\n    </div>\n</div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":610,"y":180,"wires":[[]]},{"id":"d12411f0.075428","type":"function","z":"c03635b9.79bbc","name":"","func":"var msg = {\n    \"payload\": {\n        \"speed\":Math.round(Math.random() * 60),\n        \"speed_unit\":\"MPH\",\n        \"degrees\":Math.round(Math.random() * 360)\n        \n    }\n}\nreturn msg;","outputs":1,"noerr":0,"x":470,"y":180,"wires":[["a3654026.abf898"]]},{"id":"64704468.613964","type":"ui_group","z":"","name":"Default Group","tab":"ef22f042.de6a1","disp":true,"width":"9"},{"id":"ef22f042.de6a1","type":"ui_tab","z":"","name":"Home Tab","icon":"dashboard"}]

Flow Info

created 1 week, 2 days ago
updated 1 week ago

Node Types

  • function (x1)
  • inject (x1)
  • ui_group (x1)
  • ui_tab (x1)
  • ui_template (x1)


  • wind
  • compass
  • gauge
  • meter
  • wunderground
  • pws
  • weather
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option