Select connection Type via Switch

Hello,
Is it possible to select the connection type (Bluetooth or WiFi) on the ESP32 via a Switch?
I want to count the pulses of my geigercounter and either Stream them to the cloud via WiFi or directly to my mobilewhen I am out in the field. At the same time, the Device shows all Values on a small 128x32 OLED Display. This is what I have got so far:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <BlynkSimpleEsp32_BT.h>

#define CONV_FACTOR 0.00658
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET     4
#define BLYNK_USE_DIRECT_CONNECT
#define BLYNK_PRINT Serial

int geiger_input = 18;
float voltage = 0;
long count = 0;
long countPerMinute = 0;
long timePrevious = 0;
long timePreviousMeassure = 0;
long _time = 0;
long countPrevious = 0;
float radiationValue = 0.0;
volatile unsigned long last_micros;
long debouncing = 4200;
float Dosisleistung = 0;
char auth[] = "YOUR_AUTH_HERE";

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
BlynkTimer timer;

void setup(){
  pinMode(geiger_input, INPUT);
  Blynk.setDeviceName("Geigerzähler");
  Blynk.begin(auth);
  Serial.begin(9600);
  attachInterrupt(geiger_input, countPulse, HIGH);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  display.display();
  delay(200);
  display.clearDisplay();
  timer.setInterval(5000L, sendDatatoBLClient);
}

void loop(){
  if (millis()-timePreviousMeassure > 20000){
    countPerMinute = 3*count;
    radiationValue = countPerMinute * CONV_FACTOR;
    Dosisleistung = Dosisleistung + (radiationValue / float(240.0));
    timePreviousMeassure = millis();
    float voltage = (float)analogRead(36) / 4096 * 4.2 * (3667 / 3300);
    if(Dosisleistung > 99.999){
      Dosisleistung = 0;
    }
    Serial.println("cpm = "); 
    Serial.print(countPerMinute,DEC);
    Serial.print(" - ");
    Serial.print("Dosisrate = ");
    Serial.print(radiationValue,2);
    Serial.print("uSv/h");  
    Serial.print(" - ");
    Serial.print("Equivalenz = "); 
    Serial.print(Dosisleistung,4); 
    Serial.print("uSv");    
    display.setCursor(0,0);
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.print(countPerMinute, DEC);
    display.setCursor(40, 0);
    display.print("CPM");
    display.setCursor(0,10);
    display.print(Dosisleistung,3);
    display.setCursor(40, 10);
    display.print("uSv");
    display.setCursor(0, 20);
    display.println(voltage,2);
    display.setCursor(40,20);
    display.println("V");
    if((radiationValue,2) < 9.99){
      display.setTextSize(2);
    }else{
      display.setTextSize(1);
    }
    display.setCursor(65, 10);
    display.print(radiationValue,2);
    display.setTextSize(1);
    display.setCursor(90, 25);
    display.print("uSv/h");
    display.display();
    delay(2000);
    count = 0;
  }
  Blynk.run();
  timer.run();
}
void countPulse(){
  if((long)(micros() - last_micros) >= debouncing){
    Puls();
    last_micros = micros();
  }
}
void Puls(){
  count++;
}
void sendDatatoBLClient(){
  Blynk.virtualWrite(V1, countPerMinute);
  Blynk.virtualWrite(V2, countPerMinute);
  Blynk.virtualWrite(V3, radiationValue);
  Blynk.virtualWrite(V4, radiationValue);
  Blynk.virtualWrite(V5, Dosisleistung);
  Blynk.virtualWrite(V6, Dosisleistung);
  Blynk.virtualWrite(V7, voltage);
  Blynk.virtualWrite(V8, voltage);
}

The Display and counting the pulses works fine. The only problem is, that I cant figure out how to select the Connection type. Essentially I want the ESP32 to use Bluetooth when GPIO14 is floating (LOW) and to use WiFi when it is HIGH.

I think this is totally possible to make the connection auto switch between BT and WiFi.
In the meantime, you can do it easily and quickly by rewrite code

  1. when reboot, check GPIO14
  2. if HIGH => run WiFi section of code
  3. If LOW => run BT section of code

I tried that. The Problem is, that I have to include both Libaries (BlynkSimpleEsp32_BT.h and BlynkSimpleEsp32.h). However, they both start with Blynk.begin(), and that is the problem I see there. If I want to start WiFi it uses the Bluetooth Libraries, which does not work and I get a compilation Error.
You mean something like this?

int switch = 14;
char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";
char auth[] = "YourAuthToken";

void setup(){
  if(switch = HIGH){
    Blynk.begin(auth, ssid, pass);
  }else if(switch = LOW){
    Blynk.setDeviceName("Geigercounter");
    Blynk.begin(auth);
  }
}

It seems that the 2 libraries can’t coexist. So that solution isn’t feasible, unless some modifications are done to the libs. I’ll try to find out a workaround, if possible.

Currently, using BT only is the only better solution for both scenarios.

Update
I just had a quick look, and it’s possible but IMHO, it’ll require a drastic change in the library to support this double-dip feature. I don’t feel this change is worthy now.

Update
Just find out the quick solution where you can run either BT or WiFi, selectable by GPIO14 switch. The code is much larger (almost 400K more for additional Blynk instance: 1272994 bytes compared to 888707 bytes for BT only)

This is the terminal output of the same program

  1. BT
GPIO14 LOW, Use BT
[251] 
    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ v0.6.1 on ESP32

cpm = 0 - Dosisrate = 0.00uSv/h - Equivalenz = 0.0000uSv
cpm = 0 - Dosisrate = 0.00uSv/h - Equivalenz = 0.0000uSv
cpm = 0 - Dosisrate = 0.00uSv/h - Equivalenz = 0.0000uSv
cpm = 0 - Dosisrate = 0.00uSv/h - Equivalenz = 0.0000uSv
...

  1. Reboot with GPIO14 HIGH
GPIO14 HIGH, Use WiFi
[251] Connecting to HueNet1
[4825] Connected to WiFi
[4825] IP: 192.168.2.109
[4825] 
    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ v0.6.1 on ESP32

[4831] BlynkArduinoClient.connect: Connecting to blynk-cloud.com:80
[4912] Ready (ping: 24ms).

cpm = 0 - Dosisrate = 0.00uSv/h - Equivalenz = 0.0000uSv
cpm = 0 - Dosisrate = 0.00uSv/h - Equivalenz = 0.0000uSv
cpm = 0 - Dosisrate = 0.00uSv/h - Equivalenz = 0.0000uSv
cpm = 0 - Dosisrate = 0.00uSv/h - Equivalenz = 0.0000uSv
cpm = 0 - Dosisrate = 0.00uSv/h - Equivalenz = 0.0000uSv

There must be simple mods in Blynk library, and I don’t know If you can modify them.
So I’ll post later on GitHub.

This is the modified code

#define BLYNK_PRINT Serial

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define BLYNK_USE_BT_ONLY      false //true

#if BLYNK_USE_BT_ONLY
#include <BlynkSimpleEsp32_BT_WF.h>
#else
#include <BlynkSimpleEsp32_BT_WF.h>
#include <BlynkSimpleEsp32_WF.h>
#define switch      14           // Pin D14 mapped to pin GPIO14/HSPI_SCK/ADC16/TOUCH6/TMS of ESP32
char ssid[] = "SSID";
char pass[] = "PASS";
#endif

char auth[] = "****";

#define CONV_FACTOR 0.00658
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET     4

int geiger_input = 18;
float voltage = 0;
long count = 0;
long countPerMinute = 0;
long timePrevious = 0;
long timePreviousMeassure = 0;
long _time = 0;
long countPrevious = 0;
float radiationValue = 0.0;
volatile unsigned long last_micros;
long debouncing = 4200;
float radiationDose = 0;

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
BlynkTimer timer;

bool USE_BT = true;

void setup()
{
  pinMode(geiger_input, INPUT);

  Serial.begin(115200);
  attachInterrupt(geiger_input, countPulse, HIGH);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.display();
  delay(200);
  display.clearDisplay();

#if BLYNK_USE_BT_ONLY
  Blynk_BT.setDeviceName("Geigercounter");
  Blynk_BT.begin(auth);
#else

  
  
  if (digitalRead(switch) == HIGH)
  {
    Serial.println(F("GPIO14 HIGH, Use WiFi"));
    Blynk.begin(auth, ssid, pass);
    USE_BT = false;
  }
  else
  {
    Serial.println(F("GPIO14 LOW, Use BT"));
    Blynk_BT.setDeviceName("Geigercounter");
    Blynk_BT.begin(auth);
  }
#endif

  timer.setInterval(5000L, sendDatatoBLClient);
}

void checkStatus()
{
  static float voltage;

  if (millis() - timePreviousMeassure > 20000)
  {
    countPerMinute = 3 * count;
    radiationValue = countPerMinute * CONV_FACTOR;
    radiationDose = radiationDose + (radiationValue / float(240.0));
    timePreviousMeassure = millis();

    // can optimize this calculation
    voltage = (float)analogRead(36) / 4096 * 4.2 * (3667 / 3300);

    if (radiationDose > 99.999)
    {
      radiationDose = 0;
    }

    Serial.print("cpm = ");
    Serial.print(countPerMinute, DEC);
    Serial.print(" - ");
    Serial.print("Dosisrate = ");
    Serial.print(radiationValue, 2);
    Serial.print("uSv/h");
    Serial.print(" - ");
    Serial.print("Equivalenz = ");
    Serial.print(radiationDose, 4);
    Serial.println("uSv");

    display.setCursor(0, 0);
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.print(countPerMinute, DEC);
    display.setCursor(40, 0);
    display.print("CPM");
    display.setCursor(0, 10);
    display.print(radiationDose, 3);
    display.setCursor(40, 10);
    display.print("uSv");
    display.setCursor(0, 20);
    display.println(voltage, 2);
    display.setCursor(40, 20);
    display.println("V");

    if ((radiationValue, 2) < 9.99)
    {
      display.setTextSize(2);
    }
    else
    {
      display.setTextSize(1);
    }

    display.setCursor(65, 10);
    display.print(radiationValue, 2);
    display.setTextSize(1);
    display.setCursor(90, 25);
    display.print("uSv/h");
    display.display();
    //delay(2000);


    count = 0;
  }
}

void loop()
{
  if (USE_BT)
    Blynk_BT.run();
  else
    Blynk.run();

  timer.run();
  checkStatus();
}

void countPulse() {
  if ((long)(micros() - last_micros) >= debouncing) {
    Puls();
    last_micros = micros();
  }
}
void Puls() {
  count++;
}

void sendDatatoBLClient()
{
  if (USE_BT)
  {
    Blynk_BT.virtualWrite(V1, countPerMinute);
    Blynk_BT.virtualWrite(V2, countPerMinute);
    Blynk_BT.virtualWrite(V3, radiationValue);
    Blynk_BT.virtualWrite(V4, radiationValue);
    Blynk_BT.virtualWrite(V5, radiationDose);
    Blynk_BT.virtualWrite(V6, radiationDose);
    Blynk_BT.virtualWrite(V7, voltage);
    Blynk_BT.virtualWrite(V8, voltage);
  }
  else
  {
    Blynk.virtualWrite(V1, countPerMinute);
    Blynk.virtualWrite(V2, countPerMinute);
    Blynk.virtualWrite(V3, radiationValue);
    Blynk.virtualWrite(V4, radiationValue);
    Blynk.virtualWrite(V5, radiationDose);
    Blynk.virtualWrite(V6, radiationDose);
    Blynk.virtualWrite(V7, voltage);
    Blynk.virtualWrite(V8, voltage);
  }
}

Update

Just posted on GitHub. Please give it a try and let us know.

1 Like

WOW! That totally worked! Thanks a Lot! You made my day:)

If I leave IO14 unconnected i.e. floating, it uses WiFi and if I pull it to GND, i.e. LOW, it uses Bluetooth as it is supposed to!

Thanks for all your efforts! Appreciate it!

1 Like

Great hack @khoih Just shows what a real programmer can do to make things work :slight_smile:

@Crosswalkersam However, for both a “Within WiFi router range” and “Out on the field, but still in internet range of cell (else even Blynk BT wouldn’t work)” wouldn’t simply setting a hotspot on the Cell with same SSID (as at home) do the trick? That is how I get tablets and laptops that I normally use in home, to work without any changes when on the road.

Of course this depends on your cell supplier allowing tethering

2 Likes

Thanks for your request and original code which is now included in the new hack library.
Sometimes, unusual requests :wink: , like this, can create a real headache, but we all can learn from that by doing something different and strange (hacking), hopefully helpful for other users.

Your contribution (request / code) was used (hope you don't mind) and recognized in GitHub page.

  1. Thanks to Crosswalkersam for the original code and request to inspire the work.
2 Likes

Sadly not. When I am outside, looking for radioactive rocks, I am often in the forest or in the mountains, where I either have E or no cellphone service at all. When I have the possibility to use a hotspot, I will do that.

The only issue I found was that the device does not stream the Voltage via Bt or WiFi. The Blynk app always reads 0.0000V. Thats why I had to call

voltage = (float)analogRead(36) / 4096 * 4.2 * (3667 / 3300);

twice, once in void checkStatus and once in void sendDatatoBLClient. Now it works.

I have turned it into an Instructable! https://www.instructables.com/id/Hack-GMC-Geigercounter-With-Blynk

1 Like

So nice and pro :heart_eyes:. Looking forward to your next project and idea.
Regards,

Then Blynk’s BT will not work either… basically Blynk, as an IoT product, requires constant communication link to/from the Server (the App is primarily just the GUI, not the brains).

The BT link just used the phone to act as that Device ↔ BT ↔ WiFi/Cell ↔ SERVER ↔ WiFi/Cell ↔ App link.

So unless you are also packing a portable Local Server, as an AP for both the phone/App & devices to connect too, then you will NOT get what you want with either WiFi or BT devices when out of cell/WiFi range.

I guess @Crosswalkersam meant that the cellphone is close (to use BT) as well as the cell service must be available (to use Blynk).
I also guess the reason to use this way is as follows:

  1. The SSID and PASS is hardcoded to the WiFi at home, (unless using WiFiMulti lib or similar feature to auto connect to available WiFi)
  2. Not comfortable for every user to change Cell Hotspot SSID and PASS to the same as Home WiFi.
  3. Use BT when outside in the field is the easiest way for normal user without changing anything in the code, Blynk APP

Certainly, using cell Hotspot is the better way, if possible.

I took this literally :wink: … but alas, Blynk needs some form of server connection at ALL times.

And based on many past posts… Blynk’s Bluetooth and BLE are NOT as reliable/consistent as WiFi, nor are they as fast, as they act as an additional relay to/from the Device - App - Server - App - Device

I suspect that uninitiated users expect Blynk’s BT/BLE to act like most other such Apps… as in a simple link between device and App, with NO other considerations required… which is just NOT the case with Blynk.

I already change the library so that you can run both BT and WiFi at the same time.
Can you test the code to see if it’s running OK with both (WiFi and BT) at the same time.
Note

  1. You must have 2 different Blynk projects and tokens, 1 for WiFi, one for BT.
  2. Currently, Blynk.begin() is blocking function, so that when there is no WiFi/Blynk, the code can’t run further. If this is OK, we’ll change to use non-blocking calls Blynk.config() and Blynk.connect()

The code:

#define BLYNK_PRINT Serial

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define BLYNK_USE_BT_ONLY      false    //true

#if BLYNK_USE_BT_ONLY
#include <BlynkSimpleEsp32_BT_WF.h>
#else
#include <BlynkSimpleEsp32_BT_WF.h>
#include <BlynkSimpleEsp32_WF.h>

char ssid[] = "SSID";
char pass[] = "PASS";
// WiFi Blynk token
char WiFi_auth[]  = "WiFi-token";
#endif

// BT Blynk token, not shared between BT and WiFi
char BT_auth[]    = "BT-token";

bool USE_BT = true;

#define WIFI_BT_SELECTION_PIN     14   //Pin D14 mapped to pin GPIO14/HSPI_SCK/ADC16/TOUCH6/TMS of ESP32
#define GEIGER_INPUT_PIN          18   // Pin D18 mapped to pin GPIO18/VSPI_SCK of ESP32
#define VOLTAGER_INPUT_PIN        36   // Pin D36 mapped to pin GPIO36/ADC0/SVP of ESP32  

// OLED SSD1306 128x32
#define OLED_RESET_PIN            4   // Pin D4 mapped to pin GPIO4/ADC10/TOUCH0 of ESP32
#define SCREEN_WIDTH              128
#define SCREEN_HEIGHT             32

#define CONV_FACTOR                   0.00658

#define DEBOUNCE_TIME_MICRO_SEC       4200L
#define MEASURE_INTERVAL_MS           20000L
#define COUNT_PER_MIN_CONVERSION      (60000 / MEASURE_INTERVAL_MS)
#define VOLTAGE_FACTOR                ( ( 4.2 * (3667 / 3300) ) / 4096 )

float voltage               = 0;
long  count                 = 0;
long  countPerMinute        = 0;
long  timePrevious          = 0;
long  timePreviousMeassure  = 0;
long  _time                 = 0;
long  countPrevious         = 0;
float radiationValue        = 0.0;
float radiationDose         = 0;

void IRAM_ATTR countPulse();
volatile unsigned long last_micros;

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET_PIN);
BlynkTimer timer;

void IRAM_ATTR countPulse()
{
  if ((long)(micros() - last_micros) >= DEBOUNCE_TIME_MICRO_SEC)
  {
    Pulse();
    last_micros = micros();
  }
}

void Pulse()
{
  count++;
}

void sendDatatoBlynk()
{
  //if (USE_BT)
  {
    Blynk_BT.virtualWrite(V1, countPerMinute);
    Blynk_BT.virtualWrite(V3, radiationValue);
    Blynk_BT.virtualWrite(V5, radiationDose);
    Blynk_BT.virtualWrite(V7, voltage);
  }
#if !BLYNK_USE_BT_ONLY   
  //else
  {
    Blynk_WF.virtualWrite(V1, countPerMinute);
    Blynk_WF.virtualWrite(V3, radiationValue);
    Blynk_WF.virtualWrite(V5, radiationDose);
    Blynk_WF.virtualWrite(V7, voltage);
  }
#endif 
}

void Serial_Display()
{
  Serial.print("cpm = ");
  Serial.print(countPerMinute, DEC);
  Serial.print(" - ");
  Serial.print("RadiationValue = ");
  Serial.print(radiationValue, 2);
  Serial.print("uSv/h");
  Serial.print(" - ");
  Serial.print("Equivalent RadiationDose = ");
  Serial.print(radiationDose, 4);
  Serial.println("uSv");
}

void OLED_Display()
{
  display.setCursor(0, 0);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print(countPerMinute, DEC);
  display.setCursor(40, 0);
  display.print("CPM");
  display.setCursor(0, 10);
  display.print(radiationDose, 3);
  display.setCursor(40, 10);
  display.print("uSv");
  display.setCursor(0, 20);
  display.println(voltage, 2);
  display.setCursor(40, 20);
  display.println("V");

  if ((radiationValue, 2) < 9.99)
  {
    display.setTextSize(2);
  }
  else
  {
    display.setTextSize(1);
  }

  display.setCursor(65, 10);
  display.print(radiationValue, 2);
  display.setTextSize(1);
  display.setCursor(90, 25);
  display.print("uSv/h");
  display.display();
}

void checkStatus()
{
  static float voltage;

  if (millis() - timePreviousMeassure > MEASURE_INTERVAL_MS)
  {
    timePreviousMeassure = millis();
    countPerMinute = COUNT_PER_MIN_CONVERSION * count;
    radiationValue = countPerMinute * CONV_FACTOR;
    radiationDose = radiationDose + (radiationValue / float(240.0));

    // can optimize this calculation
    voltage = (float) analogRead(VOLTAGER_INPUT_PIN) * VOLTAGE_FACTOR;

    if (radiationDose > 99.999)
    {
      radiationDose = 0;
    }

    Serial_Display();
    OLED_Display();
    
    count = 0;
  }
}

void setup()
{
  pinMode(GEIGER_INPUT_PIN, INPUT);

  Serial.begin(115200);
  attachInterrupt(GEIGER_INPUT_PIN, countPulse, HIGH);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.display();
  delay(200);
  display.clearDisplay();

#if BLYNK_USE_BT_ONLY
  Blynk_BT.setDeviceName("GeigerCounter");
  Blynk_BT.begin(BT_auth);
#else
  //if (digitalRead(WIFI_BT_SELECTION_PIN) == HIGH)
  {
    Serial.println(F("Use WiFi to connect Blynk"));
    Blynk_WF.begin(WiFi_auth, ssid, pass);
    USE_BT = false;
  }
  //else
  {
    Serial.println(F("Use BT to connect Blynk"));
    Blynk_BT.setDeviceName("GeigerCounter");
    Blynk_BT.begin(BT_auth);
  }
#endif

  timer.setInterval(5000L, sendDatatoBlynk);
}

void loop()
{
  //if (USE_BT)
    Blynk_BT.run();
#if!BLYNK_USE_BT_ONLY    
  //else
    Blynk_WF.run();
#endif

  timer.run();
  checkStatus();
}

Blynk’s Bluetooth and BLE are NOT as reliable/consistent as WiFi, nor are they as fast, as they act as an additional relay to/from the Device - App - Server - App - Device

That’s why we, you and I personally, all try to avoid using BT/BLE whenever possible.
But we can’t know what the normal users would like and are comfortable to use. :wink:

I believe @Crosswalkersam has very good reason to use this BT/WiFi way as specified in Instructables so that nothing needs to be changed in the system at all, just press a SW.

I wanted an option to use WiFi for a stationary setup at home and Bluetooth to use the device out in the field

Yep… I (once) fought the losing battle(s) to educate those fans of the old tune… “Users just wanna use BT/BLE”… but I should quit the slaughter while I still have some blood left in me :laughing:

1 Like

I’ve never felt the need to stick needles on my eyes, or use Blynk Bluetooth/BLE, but my understanding was that Bluetooth could be used in phone to server mode without any internet/GPRS connectivity.
I recall some issues about not being able to start the app (not getting past the juggling balls screen), but that was fixed by adding a facility to connect without any internet connection.

As I said, I’ve never tried this myself, so could be totally wrong.

Pete.

You don’t know what fun you are missing :crazy_face:“They’re coming to take me away ho ho hee hee ha haaa…”

Ya, I don’t recall those details… but since Account Login, Project Data and Device Authentication is supposedly stored/processed on the Server, I don’t see how that could have been overcome without total workover (which may be the case with Blynk 2.0ooomygoodnessitisneverhappening)

This was three and a half years ago, but the boss man says…

Pete.