This one only plots the top 3 WiFi Signals found (identified by router MAC address, not by name as you wouldn't believe the number of duplicate network names you'll find just walking around....) But, it stores "recent" signal strengths and uses that to plot a sort-of bar chart under the network of strength. I don't know how useful it is, but it's fairly nifty and I'm more proud than I ought to be about it.
Here's it running in a Generic Semi Public Location:
(image processed to disguise the terrible job I did of soldering on the pins)
Updated 2019-01-08 12:46: Changed the "replace with new network" code to zero-out stored and now invalid history for the old SSID.
/* A very heavily modified example of the built-in example WiFiSCAN project, aoriginally ugmented with OLED display code given in the example at: https://robotzero.one/heltec-wifi-kit-32/ and now using actual history to represent signal strength over time. Graphics library documented at https://github.com/olikraus/u8g2/wiki 2019-01-07 MCE Target Board: Heltec_WIFI_Kit_32 (with onboard 128x64 OLED) NB: Uses U8g2 ver of library to get better font-size control. After investigation, uses Full-buffer mode not so much for speed as to make debugging output less repetitive (Page buffer mode repeats the bar display / debug loop 3x per iteration due to the reasons documented at: https://github.com/olikraus/u8glib/wiki/tpictureloop ) Pretty much all the "raw data" is spewed out over the serial link for debugging purposes. No Warranty for operation or continued operation should be implied - need to do a fair amount of walking to test "handover" of top-3 networks and/or <3 available networks, and I haven't done that yet.... For reference, on the Heltec_WIFI_Kit_32 board, Sketch uses 610046 bytes (46%) of program storage space. Global variables use 43600 bytes (13%) of dynamic memory, leaving 284080 bytes for local variables. */ #include "WiFi.h" #include <U8g2lib.h> // the OLED used on the board maps to.... //PAGE LOOP mode: //U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16); //FULL BUFFER mode: U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16); //Helpers for specific font chosen setting cursor position: //Font u8g2_font_haxrcorp4089_tr is 8 wide, 10 high //Font u8g2_font_baby_tf is 10 x 10 const int FW = 10; const int FH = 11; //Actual height is 10 but this gives a little space // Arrays used to hold history info // NOTE: We only show the "top 3" SSIDs 'cos that's all we can fit onto the display // Adjust max. history in HISTSIZE to fit the width of the display (hint: 128 / 12 = 10 mod 8) const int SSIDSIZE = 3 ; //Maximum number of SSIDs for which we'll store data const int HISTSIZE = 12; //Noting that our index arithmetic needs to be 0->7.... const int SSIDLEN = 20; //Max. SSID name length we'll use (truncate if less) int PTR = 0; //the initial setting char SSIDNames[SSIDSIZE][SSIDLEN] = {"DummySSID1", "DummySSID2", "DummySSID3"}; char BSSIDidx[SSIDSIZE][18]; //We need to match against Router BSSIDs to cope with multiple access points //This is the signal strength history array. If SSIDSIZE is ever changed, this'll need updating too.... int SSIDStrength[SSIDSIZE][HISTSIZE] = { {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0} }; //Max dimensions of the bounding box we'll draw our bar segments into const int BW = 128 / HISTSIZE; const int BH = 10; //Refresh interval (ms). In practice the refresh rate is this PLUS the wifi scan interval //(which will dominate in the real world) const int REFRESHINT = 2000; //Main function to gather WiFi signal strengths and store into the data structures void gatherWiFiData(int PTR) { //Gather WiFi data digitalWrite(LED_BUILTIN, HIGH); int foundSSIDCount = WiFi.scanNetworks(); Serial.print(foundSSIDCount); Serial.println(" total SSIDs found"); digitalWrite(LED_BUILTIN, LOW); //Pass one: Did we get data that matches known BSSIDs? int foundSSID[3] = { -1, -1, -1 }; //Record index of matching BSSIDs for use in Pass two for (int i = 0; i < foundSSIDCount; ++i) { char thisSSID[SSIDLEN]; WiFi.SSID(i).toCharArray(thisSSID, sizeof(thisSSID)); Serial.print(i); Serial.print(" Found SSID: |"); Serial.print(thisSSID); Serial.print("| BSSID:"); //NOTE: BSSIDstr isn't documented but is a string-format version of the BSSID connected to... oy vey Serial.print(WiFi.BSSIDstr(i)); Serial.println("."); for (int j = 0; j < SSIDSIZE; j++) { char bssidStr[18]; WiFi.BSSIDstr(i).toCharArray(bssidStr, sizeof(bssidStr)); if (strcmp(BSSIDidx[j], bssidStr) == 0) { //Matches! Mark as found, update signal strength foundSSID[j] = i; SSIDStrength[j][PTR] = WiFi.RSSI(i); //Set current sig. strength //Debug output: Serial.print("MATCH SSID Idx "); Serial.print(i); Serial.print(" against hist. SSID Idx "); Serial.print(j); Serial.print("("); Serial.print(SSIDNames[j]); Serial.print(") setting RSSI["); Serial.print(PTR); Serial.print("] = "); Serial.println(SSIDStrength[j][PTR]); } } } //Pass two: If we DIDN'T find the SSID, replace with the N'th one... for (int j = 0; j < SSIDSIZE; j++) { if (foundSSID[j] == -1) { //entry wasn't found -> replace with n'th WiFi result (where we cap to max num of SSIds found if less) int toUse = (j < foundSSIDCount) ? j : foundSSIDCount; foundSSID[j] = toUse; //char thisSSID[SSIDLEN]; WiFi.SSID(toUse).toCharArray(thisSSID,sizeof(thisSSID)); //Convert both SSID and BSSIDstr (Strings) to relevant char* size and store: WiFi.SSID(toUse).toCharArray(SSIDNames[j], sizeof(SSIDNames[j])); WiFi.BSSIDstr(toUse).toCharArray(BSSIDidx[j], sizeof(BSSIDidx[j])); //Zero-out the existing RSSI data as we're starting with a new set: for ( int x = 0; x < HISTSIZE; x++) { SSIDStrength[j][x] = 0; } //Replace with current value: SSIDStrength[j][PTR] = WiFi.RSSI(toUse); //Debug output Serial.print("NEW SSID Idx "); Serial.print(toUse); Serial.print(" set to Hist. SSID Idx "); Serial.print(j); Serial.print("("); Serial.print(SSIDNames[j]); Serial.print(") BSSID: "); Serial.print(BSSIDidx[j]); Serial.print(" setting RSSI["); Serial.print(PTR); Serial.print("] = "); Serial.println(SSIDStrength[j][PTR]); } } } //Main function to output stored WiFi SSIDs and their associated strength histories. void showWiFiStrength(int PTR) { //Clear the screen, setup for write u8g2.clearBuffer(); u8g2.setFont(u8g2_font_baby_tf); u8g2.setFontPosTop(); //Iterate over all stored SSIDs: for (int i = 0; i < SSIDSIZE; i++) { //Print SSID on "lines" 0, 2, 4... u8g2.drawStr(4, 2 * i * FH, SSIDNames[i]); //Debug output: Serial.print(i); Serial.print(" "); Serial.println(SSIDNames[i]); //Walk through sig history using modulus arithmetic from PTR -> PTR via HISTSIZE //Walk from OLDEST (PTR+1) to NEWEST (PTR) int j = (PTR + 1) % HISTSIZE; int cnt = 0; //Absolute counter, used for bar output positioning int barTop = ((2 * i) + 1) * FH; //Starting Y-position for all bars in this output u8g2.setCursor(0, barTop); //Not, strictly, needed as we direct-plot bars anyway do { //Call our procedure to plot the bar drawSigStrengthBar(cnt, barTop, SSIDStrength[i][j]); //Debug: output index and strength Serial.print(j); Serial.print(":"); Serial.print(SSIDStrength[i][j]); Serial.print(" "); //Update the counter & pointer: j = (j + 1) % HISTSIZE; cnt++; } while ( j != PTR ); //Debug: close the per-SSID history line off Serial.println("!"); } //All elements written, actually paint the display: u8g2.sendBuffer(); } //Graphical function to plot a single bar in given index position //with height proportional to observed signal strength void drawSigStrengthBar(int xIdx, int yTop, int sigStrength) { //Scale sigStrength (expected range -40ish to -99) to a value 0 - (BH/10) //NB: we draw top to bottom, so output is INVERTED (strong signal, big bar = low offset) int barHeight = BH; //these magic numbers should really be consts at the top, but we're fiddling: if (sigStrength == 0 ) { //NaN / no value available barHeight = BH; } else if (sigStrength > -40) { // Have never observed RSSI > -40 dBM, take that as full strength //V.strong signal, max bar height barHeight = 0; } else { //Normal, do the calcs sigStrength = sigStrength + 40; // normalise by observed full-strength value barHeight = -1 * sigStrength / 6; //Range is about -40 to -99, or 60 for short, which gives 6 ints per height barHeight = (barHeight >= BH) ? BH - 1 : barHeight; //Catch out-of-range values, coerce to 1-pixel } //Our "box" for this output is calculated as TOP-LEFT: // TOP-LEFT: x=xIdx*BW, y = yTop + barHeight // BOTTOM-RIGHT: x=xIdx*BW+BW, y=yTop+BH //(note that drawBox takes TOP-LEFT, then WIDTH and HEIGHT though...) u8g2.drawBox(xIdx * BW, yTop + barHeight, BW, BH - barHeight); } // // Standard Arduino setup() / loop() functions: // void setup() { // Set WiFi to station mode and disconnect from an AP if it was previously connected WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); //Initialise the graphics library u8g2.begin(); //Setup onboard LED for output: //Used by the WiFi gatherer process only to show scanning state. pinMode(LED_BUILTIN, OUTPUT); //Support debugging.... Serial.begin(115200); } // the Master Control Loop is relatively simple...... // (if you proceduralise everything, of course....) void loop() { //Debug output marking our place: Serial.println("--------------------------------------------"); Serial.print("Iterating. Loop Index = "); Serial.println(PTR); //Get the latest WiFi strength data, populating the PTR indexed element gatherWiFiData(PTR); //Display the current SSIDs and Strength charts at the PTR indexed element showWiFiStrength(PTR); //Increment the Loop Pointer using modulus arithmetic PTR = (PTR + 1) % HISTSIZE; //And sleep until we do it all again... delay(REFRESHINT); }
I only see two bar graphs lines on my v2.0 heltec. just saying.
ReplyDeletegood work!