{"id":7928,"date":"2026-04-18T00:17:07","date_gmt":"2026-04-18T05:17:07","guid":{"rendered":"https:\/\/justinparrtech.com\/JustinParr-Tech\/?p=7928"},"modified":"2026-04-18T00:32:53","modified_gmt":"2026-04-18T05:32:53","slug":"convert-wifi-rssi-to-signal-bars-formula","status":"publish","type":"post","link":"https:\/\/justinparrtech.com\/JustinParr-Tech\/convert-wifi-rssi-to-signal-bars-formula\/","title":{"rendered":"Convert WiFi RSSI to Signal Bars (Formula and Code Snippet)"},"content":{"rendered":"<h1>Convert WiFi RSSI to Signal Bars (Formula and Code Snippet)<\/h1>\n<p>I went way down the rabbit hole trying to convert RSSI (in dBm) to a useful signal strength meter, like you&#8217;d see on your cell phone.<\/p>\n<p>I read many articles, but no one really had an algorithm.\u00a0 So&#8230;.here is an algorithm written in Javascript.<\/p>\n<p>&nbsp;<\/p>\n<h2>The Goods<\/h2>\n<pre>\/\/This assumes you have a way to obtain rssi... in my application,\r\n\/\/  this is the rssi for the web server's connection (IoT device).\r\n\r\nfunction rssiToBars( rssi , maxbars ){\r\n  var ret=rssi+80;        \/\/Useful range is -80 (bad) to -30 (good).\r\n                          \/\/+50 converts this to a useful range of 0 (bad) to 50 (good)\r\n\r\n  ret=(ret&lt; 0)?0:rssi;   \/\/Clamping\r\n  ret=(ret&gt;50)?50:rssi;\r\n\r\n  ret=parseInt(ret*maxbars\/50);    \/\/taking a percent (rssi\/50) of maxbars\r\n\r\n  \/\/ If you are using a language with integer data types, make sure you multiply\r\n  \/\/ first, then divide.\r\n\r\n  return(ret);\r\n}\r\n\r\nfunction rssiMeter( bars , maxbars ){\r\n  return(\"&lt;PRE&gt;[\" + \"#\".reapeat(bars) + \"-\".repeat(maxbars-bars) + \"]&lt;\/PRE&gt;\");\r\n\r\n  \/\/This is a simple example, but you could stack a couple of small PNG or \r\n  \/\/render a table where the cells are bars.\r\n}\r\n\r\nconst maxbars=8\r\nvar rssi=-55;   \/\/some magical way to get the rssi\r\nvar bars=rssiToBars(rssi,maxbars);\r\nvar meter=rssiMeter( bars , maxbars);\r\n\r\n\/\/ rssi  == -55\r\n\/\/ bars  ==  4\r\n\/\/ meter ==  &lt;PRE&gt;[####---]&lt;\/PRE&gt;\r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h2>How It Works<\/h2>\n<p>Received Signal Strength Indicator (RSSI) is the relative signal strength of a transmitter, from the receiver&#8217;s perspective.<\/p>\n<p>RSSI is measured in dBm, or Decibel-milliWatts.\u00a0 Basically, this is milliWatts as perceived by the receiver, but represented on a logarithmic scale.<\/p>\n<p>Because power drops inversely with the square of the distance, a logarithmic scale more or less represents this as a linear scale, rather than exponential.<\/p>\n<p>For example, if you have signal strength of -30 (very good) and you walk 50 feet away with no obstacles between you and the router, you might drop to -40 dBm.\u00a0 If you walk another 50 feet, you would expect the signal to drop to -50 dBm.\u00a0 This a super-simple example, and there are a lot of other factors involved, but you get the basic idea.<\/p>\n<p>The algorithm works like this:<\/p>\n<ol>\n<li>Convert rssi to a useful scale.\u00a0 We do this by adding 80.\u00a0 If we start with a range of -30 (good) to -80 (bad) and add 30, we get 0 (good) to -50 (bad).\u00a0 Further if we add 50, we get a positive integer that is now reversed:\u00a0 -50+50==0 (bad) and 0+50==50 (good).<\/li>\n<li>Next, we clamp the values to prevent unexpected results, ensuring we now have an integer in the range of 0..50.<\/li>\n<li>Dividing this number by 50 yields a percentage (0..1)<\/li>\n<li>Multiplying the percentage by the max number of bars, gives you the number of bars.\u00a0 For example, .5 * 8\u00a0 (medium signal strength * 8 bars) == 4.<\/li>\n<li>If using a typed language such as c++, be sure to multiply first, THEN divide:\u00a0 (rssi+50)*maxbars\/50.\u00a0 If not, the CPU will perform int math, and bars will be zero most of the time.<\/li>\n<\/ol>\n<p>Rendering can be done however you want.\u00a0 One slick trick is to use CSS and a small table, where each cell is a bar, and CSS dictates the cell color.\u00a0 Your code sets the class of each cell to &#8220;bar&#8221; or &#8220;nobar&#8221;.<\/p>\n<pre>&lt;STYLE&gt;\r\n.bar , .nobar {\r\n  height: 10px;\r\n  width: 10px;\r\n  border: 1px solid gray;\r\n  border-collapse:collaps;\r\n  font-size: 1px;\r\n}\r\n\r\n.bar{\r\n  background-color: #0000FF \/\/Blue\r\n}\r\n\r\n.nobar{\r\n  background-color: #000022 \/\/Dark Blue\r\n}\r\n&lt;\/STYLE&gt;\r\n&lt;SCRIPT&gt;\r\n  function rssiMeter( bars , maxbars ){\r\n    var meter=\"&lt;TABLE STYLE='border-collapse:collapse;'&gt;&lt;TR&gt;\";\r\n\r\n    for(var i=0 ; i&lt;maxbars ; i++){\r\n      var class=(i&lt;bars)?\"bar\":\"nobar\";\r\n      meter+=\"&lt;TD CLASS=\"+class+\"&gt;&amp;nbsp;\";  \r\n      \/\/NO I DO NOT CLOSE MY TD TAGS.  SUE ME\r\n    }\r\n\r\n    meter+=\"&lt;\/TR&gt;&lt;\/TABLE&gt;\";\r\n\r\n    return(meter);\r\n  }\r\n\r\n  \/\/ you can attach it to a DIV like this:\r\n  const maxbars=8;        \/\/ define constants at the top of your script\r\n  const divname=\"meter\"; \r\n\r\n  function updateMeter(){\r\n    var rssi = somenumber; \r\n    var bars = rssiToBars(rssi , maxbars); \/\/maxbars is a global const\r\n    var meter= rssiMeter( bars , maxbars); \r\n    document.getElementById(divname).innerHTML=meter;   \/\/divname is a global const\r\n  }\r\n\r\n  \/\/ be sure there is &lt;DIV ID=meter&gt;&amp;nbsp;&lt;\/DIV&gt;\r\n  \/\/ somewhere in your document\r\n\r\n  \/\/Now, whenever you want to update your meter:\r\n  updateMeter();\r\n\r\n&lt;\/SCRIPT&gt;<\/pre>\n<p>Enjoy!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Convert WiFi RSSI to Signal Bars (Formula and Code Snippet) I went way down the rabbit hole trying to convert RSSI (in dBm) to a useful signal strength meter, like you&#8217;d see on your cell phone. I read many articles, but no one really had an algorithm.\u00a0 So&#8230;.here is an algorithm written in Javascript. &nbsp; [&hellip;]<\/p>\n","protected":false},"author":16,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"aside","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-7928","post","type-post","status-publish","format-aside","hentry","category-other-stuff","post_format-post-format-aside"],"_links":{"self":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts\/7928","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/comments?post=7928"}],"version-history":[{"count":8,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts\/7928\/revisions"}],"predecessor-version":[{"id":7936,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts\/7928\/revisions\/7936"}],"wp:attachment":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/media?parent=7928"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/categories?post=7928"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/tags?post=7928"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}