How does GUI-O's auto-connect work in BLE?
-
@bmillier Hi!
@bmillier said in How does GUI-O's auto-connect work in BLE?:
On a happier note, I submitted my article to SE with a GUI-O project and they are processing it now. Also, another, more complex project that I am doing using GUI-O + legacy Bluetooth is working well, at this stage anyway. That project is for Circuit Cellar, but will be a ways off.
Wow, this is very nice to hear!
Regarding the BLE troubles - I will dive deeper and try to figure out what's wrong...
Since the service service and characteristic UUIDs are not standardized, I have made this user-selectable. But, if you don't want to go through this selection procedure, use NUS (Nordic UART service) UUIDs. Check out the code here BasicBLE_NUS.ino.
This basically sets a standardized service and characteristic UUID that GUI-O recognizes and connects to automatically. So, everything is the same as in the other example, just the values are different:
...SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; ...RX_CHARACTERISTIC_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"; ...TX_CHARACTERISTIC_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
I could of course add support for "GUI-O UART service" in the same way.
BR,
kl3m3n -
@kl3m3n Hi:
Yes- I think that in terms of a GUI-O - supplied BLE demo, it would make sense to use either the Nordic or UART service as a default because a newcomer would like the demo to work immediately and not have to figure out the service/characteristic. In the BLE demo C code, it would be easy to add a comment at the top explaining that a person can pick another service besides UART and maybe include commented out example code for another service.
I have some experience with BLE and the various services using the Cypress MCUs. I have to admit I am "old-fashioned": I prefer to use the simple SPP protocol and write my own parsing routines for various functions. I really don't like those really long UUIDs- they're too long to recognize/remember.
BR
Brian -
@kl3m3n Hi:
I am trying out the BasicBLE_NUS example. It acts virtually the same way as the BasicBLE example. The serial monitor on my ESP32 reports that a connection is made- almost immediately.
But, it still takes 30+ seconds and then comes up with the 3 available services: 0x1801,0x1800 and 0xFFE0. If I choose 0x1800, I then have 3 choices for characteristic: 0x2A00, 0x2A01, 0x2AA6. The 0x2A00 choice gives an error- and you have to re-boot ESP32 to try again. So does 0x2A01 and 0x2AA6
Trying service 0x1801 yields characteristic of 0x2A05 which then shows a connection but the GUI-O app just says "Connected device not responding".
Trying service 0xFFE0 yields characteristic 0xFFE1. When chosen, this shows a connection but again, the GUI-O app shows the error message "Connected device not responding".Looking at your BLE_NUS code, I cannot figure out where all of the above services/characteristics are coming from. It seems the FFE0/FFE1 values are "left over" from the BasicBLE.ino program I had tried before. I know the ESP32 caches WiFi SSIDs, etc. but wonder if it stores BLE characteristics in non-volatile Flash too?
I am wondering if this problem arises from my Android tablet, and not GUI-O code? It is an older Samsung Galaxy Tab 10.1 which I had to root and then install Lineage 16 Android OS. My wife has a much newer LG Android smartphone, but currently I only have GUI-O licensed for the Note 10.1
Sorry for all this trouble- I'm doing fine with legacy Bluetooth, so the BLE is not a deal-breaker for me- except that I can't use my ESP32-S3 which only has BLE.
BR -
@bmillier Hi
@bmillier said in How does GUI-O's auto-connect work in BLE?:
I know the ESP32 caches WiFi SSIDs, etc. but wonder if it stores BLE characteristics in non-volatile Flash too?
Can you try unpairing the ESP32 from the Android system Bluetooth menu (under settings -> Bluetooth)? It seems that you Android device has cached the "old" pairing data. Maybe this will help.
@bmillier said in How does GUI-O's auto-connect work in BLE?:
Sorry for all this trouble- I'm doing fine with legacy Bluetooth, so the BLE is not a deal-breaker for me- except that I can't use my ESP32-S3 which only has BLE.
I think that the ESP32-S3 also has WiFi? You could try the "IoT" examples? Everything is basically the same, but over WiFi (or mobile data from the Android side). "IoT" is based on MQTT protocol.
BR,
kl3m3n -
@kl3m3n Thanks-
I went into the Android Settings/Bluetooth and used "Forget this device" on the BasicBLE_NUS device, Now, it still takes 30-40 seconds (after the ESP32 says BLE has connected) to switch to the characteristic screen, but now I see the Nordic UART service. When I select this, the GUI-O demo now works. However, like you, if I close the GUI-O app, I cannot run GUI-O again until I re-boot the ESP32 (even though my ESP32 Serial monitor shows that the ESP32 BLE has disconnected).
After I re-boot the ESP-32, if I open GUI-O again (with autoconnect selected) it will successfully auto-run the demo app- but it still takes 30-40 seconds to connect.
But, the need to re-boot the ESP32 between connections is not good!
Re Wi-Fi. When I said that ESP32-S3 only has BLE, I really meant that it doesn't have legacy Bluetooth. I already have my own code for the ESP8266 or ESP32 which allows me to control/monitor an ESP32/8266 target using either Android or IOS phones/tablet with a web browser-based interface (that the ESP32/8266 serves up). Its written for a specific project- not versatile like GUI-O is, but adequate. I got interested in GUI-O for cases where Wi-fi was not available/practical- but Bluetooth was a good option.BR
-
@kl3m3n Good news! I solved the problems.
I decided to eliminate some unknowns so I tried my ESP32 running BasicBLE_NUS- connecting to my iPad running Adafruit's Bluefruit BLE Connect (utility/diagnostic app). It connected properly, I could send @init and get the GUI screen setup code back. But, when I disconnected, I could not re-connect- same as GUI-O. So, the problem was in the BasicBLE_NUS program. After some troubleshooting, I determined the problem was that the BasicBLE_NUS was failing to re-instate advertising after the disconnect. I added code to this program to start the advertising up again after a disconnect. Now both GUI-O and the Adafruit BLE Connect program run properly even after multiple disconnect/connect cycles.
Regarding the 30-40 sec delay I was experiencing. The blame for that lies with the OS on my Samsung Note 10.1 (Lineage 16). Whether I was running GUI-O or Adafruit's Bluefruit BLE Connect, it took 30-50 secs to connect with this tablet. However, running BasicBLE_NUS and connecting to my iPad, running Bluefruit BLE Connect, the connect time was instantaneous. I'm going to take this opportunity to encourage you to port GUI-O to IOS
I don't know how to attach my modified BasicBLE_NUS.ino to this message. If you want to see the code I changed, maybe give me your email address, and I can attach it to that.
BR -
@bmillier Hi
That is great news! I would be much obliged to see the modified code - I can then update the BLE examples. I would like add you as a contributor (bmiller) at the start of the example code, if it is OK with you? You can post the code patch here (just the changes) or send it to info.guio.app[at]gmail.com.
Regarding iOS - I know that in USA there are more iOS users and porting GUI-O to iOS would indeed reach a broader audience. The porting process would probably not be too difficult as most of the GUI-O source is in C++ (and I think that clang compiler allows mixing C++ with objective C code). But it is very difficult to set up an effective development environment without using a mac - and boy, are this devices expensive...
It would be awesome if the income from the GUI-O app could cover such expenses in the future. So, my reply would be - iOS is planned, but the time-frame is undetermined.
BR,
kl3m3n -
@kl3m3n Hi:
I sent the patched BasicBLE_NUS.ino file to the email address you mentioned. The added lines are marked with the comment "//BM added". I don't feel that you need to acknowledge me in the demo because I just studied a BLE uart example originally written by Neil Kolban and ported to Arduino by Evandro Copercini, and changed your demo accordingly.
I understand your issues with IOS. I had wanted to write IOS programs to act as a GUI for my MCU projects about 8 years ago. I used PCs at work and at home, but had purchased a Mac Mini because I was also doing support functions for some of our staff that used Macs exclusively. However, shortly after I got interested in trying to write IOS apps in Objective C, the Mac OS had to be updated to use it, and my Mac Mini wouldn't support the update. So, I was disappointed. Later on when Swift , Clang came along, I didn't want to spend another $1500 to buy a new Mac. Also, to be honest, I found Objective C hard to understand- I use C for everything now, but used Visual Basic on PCs and BascomAVR for the AVR MCUs I was using at that time.
As far as I know, there's nothing like your GUI-O on IOS- at least not that I've found. Since Matjaz gave me a free license, I can't see what you charge for GUI-O. But, if you decided to do an IOS version, I think you should charge more- there is not a huge market for this sort of app, but those who need it would be willing to pay more than the usual $5-$10 that apps often sell for. For IOS, there's no way the average MCU programmer is going to be able to develop their own IOS app for something like this.
BR -
@bmillier Thank you for the fix!
I have made slight modifications to keep the loop part clean and instead added your re-advertising routine to the disconnect callback. The entire example code is below at the end of this post.
I will also update the BasicBLE example. Thank you.
Yes, iOS somewhat limits the flexibility in app development. Of course, Android also enforces some changes with every new API release / update, but I don't need to buy a new PC for this
This is just my first impression - I have never really done any iOS development...P.S.: The app price on Android is around 10$. I understand there is a big market for iOS, especially in the US. The logical step would be to support this, but I currently develop the app alone and also take care of the examples, the website, the designer tool etc... Frankly, porting to iOS scares me a bit... It is going to take some time and a fair amount of energy
BR,
kl3m3n/* * GUI-O Basic BLE example (using ESP32-WROOM-32) * * Copyright (C) 2021, GUI-O Team * * SPDX-License-Identifier: BSD-3-Clause */ #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> namespace led { static const uint8_t LED_BUILTIN = 2; static const uint8_t LED_CHANNEL = 0; static const double LED_FREQ = 5000.0; static const uint8_t LED_BITS = 8; } // namespace led namespace uuid { static const char *SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; static const char *RX_CHARACTERISTIC_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"; static const char *TX_CHARACTERISTIC_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"; } // namespace uuid // forward declare parser for incoming messages void parseGuioMsg(const String &msg); // setup done flag bool setupDone = false; // custom handling of server callbacks class CustomBLEServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { Serial.println("Connected!"); }; void onDisconnect(BLEServer* pServer) { Serial.println("Disconnected!"); // fix provided by BM // restart advertising after disconnect, otherwise GUI-O cannot re-connect if(setupDone) { // restart advertising on disconnect delay(500); pServer->startAdvertising(); } } }; // custom handling of characteristic callbacks class CustomBLECharacteristicCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string msg = pCharacteristic->getValue(); // parse message string parseGuioMsg(String(msg.c_str())); } }; // global ptr BLECharacteristic *pTxCharacteristic; void setup() { // debug output Serial.begin(115200); // setup builtin led ledcSetup(led::LED_CHANNEL, led::LED_FREQ, led::LED_BITS); // channel, freq, resolution_bits ledcAttachPin(led::LED_BUILTIN, led::LED_CHANNEL); // create device BLEDevice::init("BasicBLE_NUS"); // create server and register callback BLEServer *pServer = BLEDevice::createServer(); pServer->setCallbacks(new CustomBLEServerCallbacks()); // create service BLEService *pService = pServer->createService(uuid::SERVICE_UUID); // crate Tx characteristic and add descriptor pTxCharacteristic = pService->createCharacteristic(uuid::TX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY); pTxCharacteristic->addDescriptor(new BLE2902()); // crate Rx characteristic and register callback BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(uuid::RX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR); pRxCharacteristic->setCallbacks(new CustomBLECharacteristicCallbacks()); // start the service and start advertising pService->start(); pServer->getAdvertising()->start(); // setup done flag setupDone = true; } void loop() { } /***************************/ /* IMPLEMENT YOUR GUI HERE */ /***************************/ void sendMsg(const String &msg) { pTxCharacteristic->setValue(std::string(msg.c_str())); pTxCharacteristic->notify(); delay(50); } void parseGuioMsg(const String &msg) { if(msg.startsWith("@init")) { Serial.println("GUI-O app is requesting INITIALIZATION!"); // clear screen and set background sendMsg("@cls\r\n"); sendMsg("@guis BGC:#FFFFFF\r\n"); delay(100); // initialize simple example GUI sendMsg("|LB UID:title X:50 Y:15 TXT:\"Simple light switch\" FFA:\"font8\" FSZ:3.5\r\n"); sendMsg("|LB UID:tap_me X:50 Y:70 TXT:\"TAP ME!\" FFA:\"font8\" FSZ:3 FFA:\"font5\"\r\n"); sendMsg("|CB UID:brightness X:50 Y:50 W:90 BTH:5 HAH:8 HAW:8 VIS:0 STA:135 ENA:45 FGC:#000000 SFGC:#FFFF00 BGC:#CBCBCB\r\n"); sendMsg("|IM UID:light_off X:50 Y:50 IP:\"https://i.imgur.com/3VbsS0Z.png\" VIS:1\r\n"); sendMsg("|IM UID:light_on X:50 Y:50 IP:\"https://i.imgur.com/gNdck9A.png\" VIS:0\r\n"); } else if(msg.startsWith("@light_off")) { Serial.println("GUI-O app is requesting LIGHT ON!"); // "drive GUI-O app" sendMsg("@light_off VIS:0\r\n"); sendMsg("@light_on VIS:1\r\n"); sendMsg("@brightness VIS:1 VAL:100\r\n"); // led enable ledcWrite(led::LED_CHANNEL, 255); } else if(msg.startsWith("@light_on")) { Serial.println("GUI-O app is requesting LIGHT OFF!"); // "drive GUI-O app" sendMsg("@light_off VIS:1\r\n"); sendMsg("@light_on VIS:0\r\n"); sendMsg("@brightness VIS:0 VAL:0\r\n"); // led disable ledcWrite(led::LED_CHANNEL, 0); } else if(msg.startsWith("@brightness")) { const int idx = msg.indexOf(' '); if(idx > 0) { const int val = msg.substring(idx + 1).toInt(); if(val >= 0 && val <= 100) { Serial.print("GUI-O app is requesting LIGHT BRIGHTNESS: "); Serial.println(val); // led drive ledcWrite(led::LED_CHANNEL, static_cast<uint8_t>(val * 2.55)); } } } }
-
@kl3m3n That was quick! Yes, your code which restarts the advertising in the onDisconnect routine is much better. I believe I tried putting it there first but I don't think it would compile ("not in scope" error). Then I checked out that Kolban demo and just did it his way.
You must be a pretty good programmer to be handling all aspects of this by yourself. Even programmers that do both MCU programming and either smartphone or PC applications, are often not good writers- i.e. their documentation is poor. Your's is excellent.
FYI. I have used an IOS app called TechBasic which is something like GUI-O in that it lets you communicate with MCUs via Bluetooth. It is, however, a Basic interpreter running on the IOS device. So, its a bit more versatile but you do the actual programming/development on the IOS device itself. That's not ideal. The TechBasic app itself starts up like a PC IDE for Basic programming, and you can compose/edit or select & run your Basic programs from there.. So, it's not really a stand-alone app that a non-programmer can use easily. The auto-connect feature of GUI-O is quite superior in this respect.
Also, as far as I know, IOS only works in the BLE mode- not the legacy Bluetooth SPP mode. I happen to like that the Android OS lets you use legacy Bluettoth/SPP.
So, I agree- you are right to be hesitant about an IOS app. There would be a lot of adaptation you would likely have to do.
Again- thanks for your attention and efforts on my forum posts.