{"id":3836,"date":"2021-11-30T14:00:28","date_gmt":"2021-11-30T22:00:28","guid":{"rendered":"https:\/\/www.cloudacm.com\/?p=3836"},"modified":"2021-10-02T07:21:39","modified_gmt":"2021-10-02T14:21:39","slug":"rssi-interference","status":"publish","type":"post","link":"https:\/\/www.cloudacm.com\/?p=3836","title":{"rendered":"RSSI Interference"},"content":{"rendered":"<p>Before diving right in on this topic, we should ask what is RSSI and why does interference matter. First off, RSSI stands for Received Signal Strength Indicator and it&#8217;s a measurement of the radio frequency power level present at the receiver (<a href=\"https:\/\/en.wikipedia.org\/wiki\/Received_signal_strength_indication\">1<\/a> and <a href=\"https:\/\/randomnerdtutorials.com\/nrf24l01-2-4ghz-rf-transceiver-module-with-arduino\/\">2<\/a>). A radio frequency transmitter typically has a fixed power output level. As a receiver moves away or around the transmitter, the received power level varies. RSSI is a way to measure that variation. Typically the variation follows a steady change when the receiver and transmitter have an unblocked line of sight of each other. However, objects or materials in the air can cause interference, as well as other RF transmitters that are in range. Since RF signals are only detectable with equipment, an operator of RF equipment would be unaware of the signal strength in the absence of some type of RSSI. So RSSI is a valuable tool to know the operation of the RF equipment, its limits, and factors that might further influence it.<\/p>\n<p>The ESP32-Cam project provides up to 3 possible RSSI values for 802.11 transmitters within its range of detection. The ESP32-Cam also provides a total number of detected 802.11 transmitters in range. For those 3 APs with the strongest signal strength, the ESP32-Cam provides the network name, RSSI value, and whether encryption is enabled. Here is an example, names have been changed to protect the innocent.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\">Networks\tSSID-1\tRSSID-1\tEnc-1\tSSID-2\tRSSID-2\tEnc-2\tSSID-3\tRSSID-3\tEnc-3\r\n5\tMyWifiNet\t-83\t*\tOrbNetwork\t-85\t*\tOrbNetwork\t-86\t*\r\n5\tPickers\t-89\t \tKwikPin\t-91\t*\tVinno\t-93\t*\r\n10\tJailBreak\t-84\t*\tOrbNetwork\t-84\t*\tMyWifiNet\t-87\t*\r\n4\tKwikPin\t-89\t*\tHaloNet\t-89\t*\tKwikPin\t-91\t*\r\n7\tHaloNet\t-82\t*\tPickers\t-82\t \tMixNMatch\t-89\t*\r\n14\tMyWifiNet\t-85\t*\tOrbNetwork\t-86\t*\tHaloNet\t-86\t*\r\n2\tSluther\t-92\t*\tMixNMatch\t-95\t*\t\t0\t \r\n10\tMyWifiNet\t-87\t*\tKwikPin\t-87\t*\tHaloNet\t-87\t*\r\n10\tMyWifiNet\t-87\t*\tOrbNetwork\t-88\t*\tOrbNetwork\t-89\t*<\/pre>\n<p>From the example above, these networks had more than 1 AP in range of the ESP32-Cam, &#8220;KwikPin&#8221; and &#8220;OrbNetwork&#8221;. As the ESP32-Cam location changed, the networks and RSSI values also changed. This can be used to create a heat map. But the date has some limitations. Since any network that has more than 1 AP can be read, it fails to provide details about which unique AP it is reading. The third line in the example lists &#8220;OrbNetwork&#8221;. We have no way of knowing which AP this is from the first line readings. Another significant limitation of the ESP32-Cam is it only provides higher level 802.11 RSSI values. There are other devices that use that same radio frequency that it can not detect.<\/p>\n<p>Another module that can be used to provide RSSI values from lower level RF devices is the NRF24L0. This module is capable of operating as a transceiver, which seems to be its primary use case. However the focus here will be using it to provide detected RSSI values. This code base was used for examples demonstrated below (<a href=\"https:\/\/forum.arduino.cc\/t\/poor-mans-2-4-ghz-scanner\/54846\">3<\/a>).<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2021\/10\/RSSI_TimeFreq_Domain.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3837 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2021\/10\/RSSI_TimeFreq_Domain.png\" alt=\"\" width=\"1358\" height=\"526\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2021\/10\/RSSI_TimeFreq_Domain.png 1358w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2021\/10\/RSSI_TimeFreq_Domain-300x116.png 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2021\/10\/RSSI_TimeFreq_Domain-1024x397.png 1024w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2021\/10\/RSSI_TimeFreq_Domain-768x297.png 768w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2021\/10\/RSSI_TimeFreq_Domain-604x234.png 604w\" sizes=\"auto, (max-width: 1358px) 100vw, 1358px\" \/><\/a><\/p>\n<p>The image above are the same sample of RSSI readings, but presented in the time (left) and frequency (right) domains. The code used to take these readings is here.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\">#include &lt;SPI.h&gt;\r\n\r\n\/\/ Increased define CHANNELS from 64 to 256 in attempt to increase resolution\r\n\r\n\/\/ Poor Man's Wireless 2.4GHz Scanner\r\n\/\/\r\n\/\/ uses an nRF24L01p connected to an Arduino\r\n\/\/ \r\n\/\/ Cables are:\r\n\/\/     SS       -&gt; 10\r\n\/\/     MOSI     -&gt; 11\r\n\/\/     MISO     -&gt; 12\r\n\/\/     SCK      -&gt; 13\r\n\/\/ \r\n\/\/ and CE       -&gt;  9\r\n\/\/\r\n\/\/ created March 2011 by Rolf Henkel\r\n\/\/\r\n\r\n#define CE  9\r\n\r\nunsigned long myTime;\r\n\r\n\/\/ Array to hold Channel data (32 = 1 sec, 64 = 2 sec, 128 = 4 sec, 256 = 8 sec, etc)\r\n#define CHANNELS  256\r\nint channel[CHANNELS];\r\n\r\n\/\/ greyscale mapping \r\nint  line;\r\nchar grey[] = \"0123456789\";\r\n\/\/ char grey[] = \" .:-=+*aRW\";\r\n\r\n\/\/ nRF24L01P registers we need\r\n#define _NRF24_CONFIG      0x00\r\n#define _NRF24_EN_AA       0x01\r\n#define _NRF24_RF_CH       0x05\r\n#define _NRF24_RF_SETUP    0x06\r\n#define _NRF24_RPD         0x09\r\n\r\n\/\/ get the value of a nRF24L01p register\r\nbyte getRegister(byte r)\r\n{\r\n  byte c;\r\n  \r\n  PORTB &amp;=~_BV(2);\r\n  c = SPI.transfer(r&amp;0x1F);\r\n  c = SPI.transfer(0);  \r\n  PORTB |= _BV(2);\r\n\r\n  return(c);\r\n}\r\n\r\n\/\/ set the value of a nRF24L01p register\r\nvoid setRegister(byte r, byte v)\r\n{\r\n  PORTB &amp;=~_BV(2);\r\n  SPI.transfer((r&amp;0x1F)|0x20);\r\n  SPI.transfer(v);\r\n  PORTB |= _BV(2);\r\n}\r\n  \r\n\/\/ power up the nRF24L01p chip\r\nvoid powerUp(void)\r\n{\r\n  setRegister(_NRF24_CONFIG,getRegister(_NRF24_CONFIG)|0x02);\r\n  delayMicroseconds(130);\r\n}\r\n\r\n\/\/ switch nRF24L01p off\r\nvoid powerDown(void)\r\n{\r\n  setRegister(_NRF24_CONFIG,getRegister(_NRF24_CONFIG)&amp;~0x02);\r\n}\r\n\r\n\/\/ enable RX \r\nvoid enable(void)\r\n{\r\n    PORTB |= _BV(1);\r\n}\r\n\r\n\/\/ disable RX\r\nvoid disable(void)\r\n{\r\n    PORTB &amp;=~_BV(1);\r\n}\r\n\r\n\/\/ setup RX-Mode of nRF24L01p\r\nvoid setRX(void)\r\n{\r\n  setRegister(_NRF24_CONFIG,getRegister(_NRF24_CONFIG)|0x01);\r\n  enable();\r\n  \/\/ this is slightly shorter than\r\n  \/\/ the recommended delay of 130 usec\r\n  \/\/ - but it works for me and speeds things up a little...\r\n  delayMicroseconds(100);\r\n}\r\n\r\n\/\/ scanning all channels in the 2.4GHz band\r\nvoid scanChannels(void)\r\n{\r\n  disable();\r\n  for( int j=0 ; j&lt;200  ; j++)\r\n  {\r\n    for( int i=0 ; i&lt;CHANNELS ; i++)\r\n    {\r\n      \/\/ select a new channel\r\n      setRegister(_NRF24_RF_CH,(128*i)\/CHANNELS);\r\n      \r\n      \/\/ switch on RX\r\n      setRX();\r\n      \r\n      \/\/ wait enough for RX-things to settle\r\n      delayMicroseconds(40);\r\n      \r\n      \/\/ this is actually the point where the RPD-flag\r\n      \/\/ is set, when CE goes low\r\n      disable();\r\n      \r\n      \/\/ read out RPD flag; set to 1 if \r\n      \/\/ received power &gt; -64dBm\r\n      if( getRegister(_NRF24_RPD)&gt;0 )   channel[i]++;\r\n    }\r\n  }\r\n}\r\n\r\n\/\/ outputs channel data as a simple grey map\r\nvoid outputChannels(void)\r\n{\r\n  int norm = 0;\r\n  \r\n  \/\/ find the maximal count in channel array\r\n  for( int i=0 ; i&lt;CHANNELS ; i++)\r\n    if( channel[i]&gt;norm ) norm = channel[i];\r\n    \r\n  \/\/ now output the data\r\n  for( int i=0 ; i&lt;CHANNELS ; i++)\r\n  {\r\n    int pos;\r\n    \r\n    \/\/ calculate grey value position\r\n    if( norm!=0 ) pos = (channel[i]*10)\/norm;\r\n    else          pos = 0;\r\n    \r\n    \/\/ boost low values\r\n    if( pos==0 &amp;&amp; channel[i]&gt;0 ) pos++;\r\n    \r\n    \/\/ clamp large values\r\n    if( pos&gt;9 ) pos = 9;\r\n   \r\n    \/\/ print it out\r\n    Serial.print(grey[pos]);\r\n    Serial.print(',');\r\n    channel[i] = 0;\r\n  }\r\n  \r\n  \/\/ indicate overall power\r\n  Serial.print(norm);\r\n  Serial.print(',');\r\n  myTime = millis();\r\n  Serial.print(myTime);\r\n  Serial.println(',');\r\n}\r\n\r\n\r\nvoid setup()\r\n{\r\n  Serial.begin(57600);\r\n  \r\n  \/\/ Setup SPI\r\n  SPI.begin();\r\n  \/\/ Clock Speed, Bit Order, and Data Mode\r\n  SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0));\r\n  \r\n  \/\/ Activate Chip Enable\r\n  pinMode(CE,OUTPUT);\r\n  disable();\r\n  \r\n  \/\/ now start receiver\r\n  powerUp();\r\n  \r\n  \/\/ switch off Shockburst\r\n  setRegister(_NRF24_EN_AA,0x0);\r\n  \r\n  \/\/ make sure RF-section is set properly \r\n  \/\/ - just write default value... \r\n  setRegister(_NRF24_RF_SETUP,0x0F); \r\n  \r\n  \/\/ reset line counter\r\n  line = 0;\r\n}\r\n\r\nvoid loop() \r\n{ \r\n  \/\/ do the scan\r\n  scanChannels();\r\n  \r\n  \/\/ output the result\r\n  outputChannels();\r\n}<\/pre>\n<p>The code generates text that is output on an Arduino Uno serial transmit pin. Putty was used to log the serial stream and save it as a csv file. The resulting file was opened as a spreadsheet and the last 2 columns were used to chart the time domain RSSI values. The frequency domain values could be visualized in the spreadsheet as well using cell value conditions, but this wasn&#8217;t efficient. Python was used instead, but the resulting image required some post process normalization, here is the code.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from numpy import genfromtxt\r\nnumpy_array = genfromtxt('C:\/Share\/Python\/RSSI Readings_New_256-Resolution.csv', delimiter=',')\r\n\r\nimport cv2\r\ncv2.imwrite('C:\/Share\/Python\/RSSI Readings_New_256-Resolution.png', numpy_array)\r\n\r\n<\/pre>\n<p>Python libraries used in the example will need to be installed. These steps worked for the examples above. The last video was relevant for the Linux hosts.<\/p>\n<p><iframe loading=\"lazy\" title=\"How to Download and Install Python latest version in Windows 11\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/VWgs_iTojoA?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><br \/>\n<iframe loading=\"lazy\" title=\"How to install NumPy SciPy Pandas Matplotlib libraries for Python in Windows 10\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/yo1oaiM_-nY?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p>There are commercial products that can provide visibility, but the costs for these devices put them out of reach for casual users. Here are list of resources for products used for professional work.<\/p>\n<ul>\n<li><a href=\"https:\/\/www.oscium.com\/spectrum-analyzers\/wipry-2500x\">https:\/\/www.oscium.com\/spectrum-analyzers\/wipry-2500x<\/a><\/li>\n<li><a href=\"https:\/\/shop.metageek.com\/products\/metageek-complete\">https:\/\/shop.metageek.com\/products\/metageek-complete<\/a><\/li>\n<li><a href=\"https:\/\/shop.nutsaboutnets.com\/\">https:\/\/shop.nutsaboutnets.com\/<\/a><\/li>\n<\/ul>\n<p>In addition to the cost, these devices aren&#8217;t designed to be placed on a remote controlled device or carried aloft using other means due to their size, weight, and power requirements. The RSSI value readings offered by the NRF24L0 provides a wealth of information for its low cost and small size. Be aware though that the manufacturer has indicated that this device should not be used for new designs (<a href=\"https:\/\/www.nordicsemi.com\/Products\/nRF24-series\">4<\/a> and <a href=\"https:\/\/www.nordicsemi.com\/-\/media\/Publications\/WQ-Product-guide\/Wireless-Q---Q1---Product-Guide.pdf\">5<\/a>). Nordic semiconductors is currently offering nRF9 and nRF5 series devices for new designs. Of these new device offerings, Adafruit offers a guide for the nRF51822 (<a href=\"https:\/\/learn.adafruit.com\/introducing-the-adafruit-bluefruit-le-sniffer?view=all\">6<\/a>).<\/p>\n<p>For operators of radio controlled equipment, RSSI readings are often a built in feature. FlySky offers a reasonably priced TX and their RX options offer RSSI values back to the TX. These readings provide the operator with information that can prevent a loss of signal condition. However, the RSSI values the RX provides is also limited in detail. It only provides its RSSI value from the bound TX. The operator has no way of knowing about other devices transmitting in the area. Although FlySky has limited RSSI data, it does offer other features from its iBus support, which will be covered in the next post.<\/p>\n<p>Footnotes<\/p>\n<p>(1) <a href=\"https:\/\/en.wikipedia.org\/wiki\/Received_signal_strength_indication\">https:\/\/en.wikipedia.org\/wiki\/Received_signal_strength_indication<\/a><br \/>\n(2) <a href=\"https:\/\/randomnerdtutorials.com\/nrf24l01-2-4ghz-rf-transceiver-module-with-arduino\/\">https:\/\/randomnerdtutorials.com\/nrf24l01-2-4ghz-rf-transceiver-module-with-arduino\/<\/a><br \/>\n(3) <a href=\"https:\/\/forum.arduino.cc\/t\/poor-mans-2-4-ghz-scanner\/54846\">https:\/\/forum.arduino.cc\/t\/poor-mans-2-4-ghz-scanner\/54846<\/a><br \/>\n(4) <a href=\"https:\/\/www.nordicsemi.com\/Products\/nRF24-series\">https:\/\/www.nordicsemi.com\/Products\/nRF24-series<\/a><br \/>\n(5) <a href=\"https:\/\/www.nordicsemi.com\/-\/media\/Publications\/WQ-Product-guide\/Wireless-Q---Q1---Product-Guide.pdf\">https:\/\/www.nordicsemi.com\/-\/media\/Publications\/WQ-Product-guide\/Wireless-Q&#8212;Q1&#8212;Product-Guide.pdf<\/a><br \/>\n(6) <a href=\"https:\/\/learn.adafruit.com\/introducing-the-adafruit-bluefruit-le-sniffer?view=all\">https:\/\/learn.adafruit.com\/introducing-the-adafruit-bluefruit-le-sniffer?view=all<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Before diving right in on this topic, we should ask what is RSSI and why does interference matter. First off, RSSI stands for Received Signal Strength Indicator and it&#8217;s a measurement of the radio frequency power level present at the receiver (1 and 2). A radio frequency transmitter typically has a fixed power output level. As a receiver moves away or around the transmitter, the received power level varies. RSSI is a way to measure that variation. Typically the variation&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.cloudacm.com\/?p=3836\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-3836","post","type-post","status-publish","format-standard","hentry","category-rd"],"_links":{"self":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/3836","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3836"}],"version-history":[{"count":8,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/3836\/revisions"}],"predecessor-version":[{"id":3839,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/3836\/revisions\/3839"}],"wp:attachment":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3836"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3836"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3836"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}