🔍

Wifi Outdoor Gaming Console

basic prototype

This ESP32 based minimalistic console uses sourrounding wifi signals as playground components. Amount of available networks, signal strength and ssid makes a pretty interesting view to our suburban world outdoors.

#include <Arduino.h>

#include <btn.h>
#include <trx_eeprom.h>


#include <Adafruit_GFX.h>                                  // Core graphics library
#include <Adafruit_ST7735.h>  
#define LED_BUILTIN 22
Adafruit_ST7735 tft = Adafruit_ST7735(16, 17, 23, 5, 9); // CS,A0,SDA,SCK,RESET


#include "WiFi.h"

// -----------------------------

// -----------------------------

	uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3); }

#define RGB(r, g, b) (((r&0xF8)<<8)|((g&0xFC)<<3)|(b>>3))

#define GREY RGB(99,99,99)

// -------------------------------

bool containsSubstring(String string, String substrings[], int numSubstrings) {
    for (int i = 0; i < numSubstrings; i++) {
        if (string.indexOf(substrings[i]) >= 0) {
            return true;
        }
    }
    return false;
}


String string = "The quick brown fox jumps over the lazy dog";
String substrings[] = {"Vodafone", "FRITZ", "cat"};
int numSubstrings = 3;

// ----------------------------------

int hi_count = 0;
int mid_count = 0;
int low_count = 0;
int all_count = 0;

uint16_t returnColorBySignalStrength(int _s){

    uint16_t rcc = GREY;

    if(_s>=85){ rcc = GREY;  low_count++;}
    if(_s<85 && _s>=65){ rcc = ST7735_ORANGE;  mid_count++;}
    if(_s<65){ rcc = ST7735_GREEN;  hi_count++;}

    return rcc;

}





class aNODE { 
  public:
    char* ssid;
    int rssi;
    aNODE() {
    }
};
 
char ssid_buffer_str[32]; // allocate a buffer for the input string
//uint8_t* bitmap; // pointer to the bitmap array

aBTN BTN1(35,true);
aBTN BTN2(34,true);

void stringToBitmap(const char* str, uint8_t* bitmap, size_t len) {
  for (size_t i = 0; i < len; i++) {
    bitmap[i] = 0;
  }
  for (size_t i = 0; i < strlen(str); i++) {
    char c = str[i];
    for (int j = 0; j < 8; j++) {
      if (c & (1 << j)) {
        bitmap[i * 8 + j] = 1;
      }
    }
  }
}

int return_score_calc(int _n){

   int rv = 0;

    if(_n == 0){rv += 1000;} // when no wlan around - add 100 points!
    if(_n > 0 && _n <=5 ){rv += 500;} // 
    if(_n > 5 && _n <=10 ){rv += 100;} // 

    if( hi_count == 0 &&  mid_count == 0){ rv += 50;}

    // negative
    if( hi_count > 0 ||  mid_count > 0){ rv -= 100;}
    if( _n > 50 ){ rv -= 40;}

    rv -=  _n;

    return rv;
}


// --------------------------------------

void update_base_data(int _n){

  if(max_wlans < all_count ){

    max_wlans = all_count;

    
  }
  Serial.println("-----------------");
  Serial.println(main_score);
 int offset =  return_score_calc( _n);
  main_score += offset;
  if(main_score<0){main_score=0;}

   
   Serial.print(" off: ");Serial.println(offset);
   Serial.print(" clculated score is: ---------------"); Serial.println(main_score);
  
  

  tft.setTextColor(ST7735_BLUE);
  tft.setCursor(60,120);
  tft.print("score:");
  tft.println(main_score);
  tft.setCursor(1,122);
  tft.print("max:");
  tft.println(max_wlans);

  //tft.fillRect( 58,68,40,8,ST7735_CYAN);
  tft.setCursor(50,77);
  tft.setTextSize(2);
   tft.setTextColor(ST7735_CYAN);
   tft.print(offset);

    delay(100);
   update_EPROM();

}


// -----------------



void wifi_scanned(int n) {

 

    tft.fillScreen(ST7735_BLACK);

    int row = 0;
    int col = 0;
    int gscl = 2;


  hi_count = 0;
  mid_count = 0;
  low_count = 0;
  all_count = 0;

 

  if (n == 0) {
      Serial.println("no networks found");



  } else {
   
    all_count = n;
 

    for (int i = 0; i < n; ++i) {

      uint16_t cc = GREY;
 
      int ss = -int(WiFi.RSSI(i));

/*  
      aNODE newNode = aNODE();

      String cssid = WiFi.SSID(i);

      char* myChar = strdup(cssid.c_str()); // Convert the String to char*

      newNode.ssid = myChar;
      free(myChar);
     // free(cssid);

      newNode.rssi = ss;
      allNodes[i] = newNode;
*/ 
        cc =  returnColorBySignalStrength(ss);
       tft.fillRect((col)*gscl+4,(row)*gscl+4,1,1, cc   );

        if(col > 60){
          col = 0;
          row++;
        }else{
          col++;
        }


    }

    // -------------------------------------------------------
     // -------------------------------------------------------

    tft.fillRect(0,22,40,18,ST7735_GREEN);
    tft.fillRect(42,22,40,18,ST7735_ORANGE);
    tft.fillRect(84,22,40,18,GREY);

     tft.setTextColor(ST7735_BLACK);
      tft.setCursor(2,24);
      tft.setTextSize(2);
      tft.print(hi_count);

      tft.setCursor(44,24);
      tft.print(mid_count);
      
       tft.setCursor(84,24);
      tft.print(low_count);
      //

      tft.setTextColor(ST7735_WHITE);
      tft.setTextSize(1);
       tft.setCursor(100,4);
       tft.print("=");
       tft.println(all_count);

// -----------------------------------------------------------
       
       tft.setCursor(0,42);
       tft.setTextSize(1);
       tft.setTextColor(ST7735_WHITE);
       tft.setTextWrap(false);
       int step = 0;
       for (int i = 0; i < n; ++i) {


          if (containsSubstring(WiFi.SSID(i), substrings, numSubstrings)) {
          //Serial.println("The string contains at least one of the substrings.");
            
           } else {
         // Serial.println("The string does not contain any of the substrings.");

            int ss = -int(WiFi.RSSI(i));


            uint16_t _cc =  returnColorBySignalStrength(ss);
            tft.setTextColor(_cc);

          tft.print( ss );
           tft.print("-");
          tft.println( WiFi.SSID(i));
          step++;
          }

       }



  }
 // Serial.println("");

    // Delete the scan result to free memory for code below.
    WiFi.scanDelete();

    update_base_data(n);


}

 




// ---------------------------------------------


void setup()
{


     pinMode(27,OUTPUT);//Backlight:27
    analogWrite(27,8);//New version added to backlight control
    tft.initR(INITR_18GREENTAB);                             // 1.44 v2.1
    tft.fillScreen(ST7735_BLACK);                            // CLEAR
    pinMode(LED_BUILTIN, OUTPUT);

    init_EEPROM();

     Serial.begin(9600);

     

    // Set WiFi to station mode and disconnect from an AP if it was previously connected.
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);



    Serial.println("Setup done");
    
    
}


// ----------------------------------------------

void loop() {
  // put your main code here, to run repeatedly:
BTN1.operateBUTTON();
BTN2.operateBUTTON();


if(BTN1.on_pressed){
  reset_All();
  return;
}


if(BTN2.on_pressed){
   WiFi.scanNetworks(true);
   read_EEPROM();
}

  
  // print out Wi-Fi network scan result upon completion
  int n = WiFi.scanComplete();
  if(n >= 0)
  {
      wifi_scanned(n);
  }

  if(n==-1){

      tft.fillRect(30,0,60,16,ST7735_WHITE);
      tft.setCursor(50 + random(-2,2),4);
      tft.setTextColor(ST7735_BLUE);
      tft.println("SCAN");

      tft.fillRect(random(0,128),random(0,128),2,2,ST7735_CYAN);

  }
  


  delay(4);
}

 

int max_wlans = 1;
int no_wlan_around_tick = 1;
#include <EEPROM.h>
 
int main_score = 0;

#define EEPROM_SIZE 1024


    // 0 - has data
    // 1 - max wlans
    // 2 - no_wlan_around_tick


void writeIntToEEPROM(int address, int value) {
  byte highByte = highByte(value);
  byte lowByte = lowByte(value);

  EEPROM.write(address, highByte);
  EEPROM.write(address + 1, lowByte);

  EEPROM.commit();
}

int readIntFromEEPROM(int address) {
  byte highByte = EEPROM.read(address);
  byte lowByte = EEPROM.read(address + 1);

  return (highByte << 8) + lowByte;
}


void read_EEPROM(){

     
    //has_data = EEPROM.read(0);
    main_score = readIntFromEEPROM(0);
    max_wlans =  readIntFromEEPROM(1); //  readIntFromEEPROM(1);
   // no_wlan_around_tick = EEPROM.read(2); 
   

    Serial.println ("read from eprom -----------");
    Serial.print ("score");
    Serial.println(main_score);


}

void init_EEPROM(){

     
     EEPROM.begin(EEPROM_SIZE);
    read_EEPROM();
 
}

 



void update_EPROM(){

    Serial.println ("xxxxxxxxxxxxx WRITE TO PRO -----------");
    Serial.print ("score");
    Serial.println(main_score);

    //EEPROM.put(0, (int)main_score);
    //EEPROM.put(1, (int)max_wlans);

    writeIntToEEPROM(0,main_score);
     
     EEPROM.commit();
     
     Serial.println (" .........   commited ........... ");

    //read_EEPROM();

}

// ---------------------------------

 void reset_All(){

    main_score = 0;
    max_wlans = 0;
    
    //EEPROM.writeInt(2, no_wlan_around_tick);

    update_EPROM();
    read_EEPROM();
 }


// -------------------------------
// TXY'S button helper class
// --------------------------------
// serves you wonderful functionality right on the plate :)
  
    // is_pressed = momentary state of button
    // is_holded = momentary state if button is down for at least 1s
      
    // on_pressed = triggered once if button is down
    // on_pressed = triggered once if button is up
    // on_holded = triggered once if button is down for at least 1s
  
  
class aBTN {
  private:
    int bpin;
    long ts = 0;
    bool previous_state = false;
    bool prev_is_holded = false;
    bool flipped_phase = false;
  
  public:
    bool is_pressed = false;
    bool is_holded = false;
  
    bool on_pressed = false;
    bool on_released = false;
    bool on_holded = false;
  
    aBTN(int bpin, bool _flipped_phase) {
      this->bpin = bpin;
      this->flipped_phase = _flipped_phase;
      init();
    }
    void init() {
      pinMode(bpin, INPUT);
  
    }
  
  
    void operateBUTTON() {
  
      this->is_pressed = digitalRead(bpin);
  
        // flip phase if button phase is flipped
       if(this->flipped_phase){this->is_pressed = !this->is_pressed;}
  
        // reset press states
      this->on_pressed = false;
      this->on_released = false;
  
      // if there is any change of state :)
      if (this->previous_state != this->is_pressed) {
  
  
            if (this->is_pressed) {
              
            //button is pressed down -------
            this->ts = millis(); // set timestamp
            this->on_pressed = true;
  
            } else {
            //button is released -------
            this->on_released = true;
            this->is_holded = false;
            this->on_holded = false;
            this->prev_is_holded = false;
            }
  
            // buffer prev state to avoid repeat
            this->previous_state = this->is_pressed;
  
      }
  
        // reset on hold state first
        this->on_holded = false;
  
        // if button is holded for more than 1s and is still pressed!
      if (this->ts + 1000 < millis() && this->is_pressed ) {
  
        this->is_holded = true; // set is holded state each frame here
  
        if (this->prev_is_holded != this->is_holded && this->is_pressed ) {
  
          this->on_holded = true;
          this->prev_is_holded = this->is_holded;
            
        }
      }
    }
};