Is there a possibility how to "overcome" BLE MAC address randomization and detect presence of my own Android phone(s)?
I'm looking for a solution how to detect presence of my phone in close-range to ESP32 without installing something like iBeacon app which would drain my battery.
I've started with example for BLE sniffer which works nice but with MAC randomization on Android it is useless.
Then I moved to the solution using emulation of a HID keyboard. After pairing it, it is nicely reconnecting when the phone comes into the range. Once it is connected I can trigger needed action and then I can turn ESP32 Bluetooth off not to be connected whole time. When I need check the phone again I just can turn the server back on. It would be neat solution but... I need to check more (at least two) phones. I've tried to duplicate BLEServers to swith between or run two simoutinasly but without success - either it is not possible or it is exceeding my knowladge about this BLE advertising/pairing/connecting magic.
Third solution would be to have separate ESP for each phone - doable but only as a last resort
Has somebody solved such task somehow already?
For the keyboard solution I'm using this code found online:
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include "BLE2902.h"
#include "BLEHIDDevice.h"
#include "HIDTypes.h"
#include "HIDKeyboardTypes.h"
#include <driver/adc.h>
BLEHIDDevice* hid;
BLECharacteristic* input;
BLECharacteristic* output;
BLEAdvertising *pAdvertising;
BLEServer *pServer;
bool connected = false;
bool restart = false;
class MyCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer){
connected = true;
Serial.println("Connected");
BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
desc->setNotifications(true);
// NEEDED ACTIONS
}
void onDisconnect(BLEServer* pServer){
connected = false;
Serial.println("DisConnected");
BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
desc->setNotifications(false);
restart = true;
}
};
void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");
BLEDevice::init("Backpack-MeowMeow");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyCallbacks());
pServer->getPeerDevices(true);
hid = new BLEHIDDevice(pServer);
input = hid->inputReport(1); // <-- input REPORTID from report map
output = hid->outputReport(1); // <-- output REPORTID from report map
std::string name = "ElectronicCats";
hid->manufacturer()->setValue(name);
hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
hid->hidInfo(0x00,0x02);
BLESecurity *pSecurity = new BLESecurity();
// pSecurity->setKeySize();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
hid->startServices();
pAdvertising = pServer->getAdvertising();
pAdvertising->setAppearance(HID_BARCODE);
pAdvertising->addServiceUUID(hid->hidService()->getUUID());
pAdvertising->start();
hid->setBatteryLevel(7);
//ESP_LOGD(LOG_TAG, "Advertising started!");
//delay(portMAX_DELAY);
}
void loop() {
if(connected){
delay(10);
}
if (restart) {
restart = false;
pAdvertising->start();
}
delay(50);
}
Related
I'm using a bluetooth modul (HC-05) to detect if an android phone is in the modul's range.
I tried to connect with HC-05 (as master) and a PIC16f887 to the phone, but I can't. Searched many pages on net how to use HC-05 as master, but no solution.
So, finally I could do this by modul get my phone's BT name. If it could, my phone is in range.
But now I want my phone to detect this "remote name query" and play some sound then.
Sorry for my poor english :)
Im guessing you want something like this: VIDEO
Lets start with the basics:
The typical default factory settings for a new Bluetooth HC-05 module are:
Default Bluetooth Name: “HC-05”
Default Password: 1234 or 0000
Default Communication: Slave Device
Default Mode: Data Mode
Default Data Mode Baud Rate: 9600, 8, N, 1
Default Command Mode Baud Rate: 38400, 8, N, 1
Default firmware: LINVOR
1. To TEST Bluetooth connections from your android device use id suggest you use this APK
2. Connect the HC-05 BT module as shown in the diagram
3. Initialize the UART receiver at the microcontroller end (side)
(code includes 2 leds for pin 33 and pin 34)
/*
* LAB Number: 17
* LAB Name: Bluetooth Module HC-05 Interfacing (Smartphone -> MCU)
* Author: Khaled Magdy
* For More Information Visit My Website # DeepBlueMbedded.com
*
*/
#include <xc.h>
#include <stdint.h>
#include "config.h"
#define _XTAL_FREQ 4000000
//--[ Control Data ]--
#define Blue_LED_ON 49
#define Blue_LED_OFF 50
#define Yellow_Toggle 51
//--------------------------------
// Functions Declarations
void UART_RX_Init(void);
// Globals
uint8_t UART_Buffer = 0;
//--------------------------------
// Main Routine
void main(void)
{
//--[ Peripherals & IO Configurations ]--
UART_RX_Init(); // Initialize The UART in Master Mode # 9600bps
TRISB0 = 0; // Blue LED (Switch)
TRISB1 = 0; // Yellow LED (Toggle)
RB0 = 0; // Initially OFF
RB1 = 0; // Initially OFF
//---------------------------
while(1)
{
}
return;
}
//--------------------------------
// Functions Definitions
void UART_RX_Init()
{
BRGH = 1; // Set For High-Speed Baud Rate
SPBRG = 25; // Set The Baud Rate To Be 9600 bps
// Enable The Ascynchronous Serial Port
SYNC = 0;
SPEN = 1;
// Set The RX-TX Pins to be in UART mode (not io)
TRISC6 = 1; // As stated in the datasheet
TRISC7 = 1; // As stated in the datasheet
//--[ Enable UART Receiving Interrupts ]--
RCIE = 1; // UART Receving Interrupt Enable Bit
PEIE = 1; // Peripherals Interrupt Enable Bit
GIE = 1; // Global Interrupt Enable Bit
//------------------
CREN = 1; // Enable Data Continous Reception
}
void interrupt ISR (void)
{
if (RCIF == 1)
{
UART_Buffer = RCREG; // Read The Received Data Buffer
// This could have been done within the main loop. Since it's not
// Excessive processing, so it's OK to do it here below
if(UART_Buffer == Blue_LED_ON)
RB0 = 1; // Blue LED ON
if(UART_Buffer == Blue_LED_OFF)
RB0 = 0; // Blue LED OFF
if(UART_Buffer == Yellow_Toggle)
RB1 = ~RB1; // Toggle Yellow LED
RCIF = 0; // Clear The Interrupt Flag
}
}
NOTE The Data Bytes (49, 50, and 51) are the ASCII equivalents for the numeric characters (1, 2, and 3 respectively).
4. Download this apk to send commands to your HC05: APK
For more info follow Reference: LINK
I've run into some weird behaviour and looks like I can't find an answer. I've written some simple code to control a servo motor via bluetooth using my phone.
#include <Servo.h>
#include "SoftwareSerial.h";
int servoPin = 2;
int bluetoothTx = 11;
int bluetoothRx = 10;
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
Servo myservo;
char unChar;
String readString;
void setup() {
Serial.begin(9600);
bluetooth.begin(115200);
delay(100);
bluetooth.begin(9600);
myservo.attach(servoPin, 800, 2200);
}
void loop() {
if (bluetooth.available()) {
unChar = bluetooth.read();
Serial.println(unChar);
if (unChar == 'A') {
motor();
}
}
}
void motor() {
delay(15);
while (bluetooth.available()) {
char c = bluetooth.read();
readString += c;
}
if (readString.length() > 0) {
Serial.println(readString.toInt());
myservo.write(readString.toInt());
readString = "";
}
}
For android, I used the MIT App Inventor to make a basic slider.
I'm using an Arduino Mega 2560, Power HD High-Torque High-Voltage Digital Servo 1218TH and a Bluetooth Mate Silver RN-41.
Everything works fine with the exception of the servo stuttering while dragging the slider on the phone. That is one small problem. The weird behaviour appears when I comment or delete my code in the arduino loop. The servo still stutters on its place when I play with the slider. What causes this behaviour?
Try to re-adjust the delay time after delete comment, it happens because add debug log inside the loop needs time to show up. In other words, that comment inside the loop has an impact on delay time.
I have battled this issue for a while now and it is driving me nuts:
I am trying to communicate very simply with an Arduino Mega 2560 (via USB as a serial device) from pc running Linux (Knoppix on a usb-dok) when all I am trying to accomplish at this stage is that for each number sent by the laptop to the Arduino, a 'stobe' signal will switch for High to Low or the other way around, and i use this strobe to light turn an LED on and off.
pc side C code:
#include <stdio.h>
int main ()
{
FILE * Device = NULL;
int counter = 0;
Device = fopen("/dev/ttyACM0", "w+");
if(Device == NULL)
{
printf("could not open Device\n");
return -1;
}
while (counter < 10)
{
fprintf(Device, "%d\n", counter);
printf("Sent to Device: %d\n", counter);
counter++;
sleep(2);
}
fclose(Device);
return 0;
}
Arduino code:
int cnt = 0;
int strobe = 0;
int num;
int ValidInput = 0;
char intBuffer[12];
String intData = "";
int delimiter = (int) '\n';
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(3, OUTPUT);
}
int input;
void loop()
{
while(num = Serial.available())
{
delay(5);
// Serial.println(num);
int ch = Serial.read();
if(ch == delimiter)
{
ValidInput = 1;
break;
}
else
{
intData += (char) ch;
}
}
int intLen = intData.length() + 1;
intData.toCharArray(intBuffer, intLen);
intData = "";
int i = atoi(intBuffer);
if(ValidInput)
{
if(i == 0)
{
strobe = 0;
Serial.print("Initializing strobe");
}
else
{
strobe = !strobe;
}
digitalWrite(3, (strobe) ? HIGH : LOW);
Serial.println(i);
ValidInput = 0;
}
}
The problems I am having:
Not sure if fopen is the correct way to communicate with a serial device in Linux, and if so in which mode?
This is the main issue - I am experiencing non-deterministic behavior:
if i run this code right before opening the Arduino editor's 'Serial monitor' it doesn't work as I explained above, instead - it will turn the LED on and then off right away, for each incoming new number.
but once I open the 'Serial monitor' it would act as I want it to - changing the LED's state for each new incoming number.
I am thinking this has something to do with the Arduino's reset or something of that sort.
I looked in many threads here and other forums and couldn't find any solution to this problem.
I'd really appreciate your insight.
First of all, the arduino side looks ok. On the Linux side you need to do some reasearch since the serial communication on posix systems is a little bit more complicated than only opening a file and writing to it. Please use the linux man pages for termios where you can find information on how to setup the communication port parameters and use this document http://tldp.org/HOWTO/Serial-Programming-HOWTO/ for actually learning how to put everything altogether. The serial programming howto will guide you through the process of setting up a port, learning how to control it and learn how to accept input from multiple sources. Also in order to access successfully the serial port from an unprivileged account, you might need to add that user (your user) to a specific group (dialout group in Ubuntu and Fedora). You can search on Google about serial port access under linux and you can fine a lot of code samples ready for you to integrate in your application. You can find an excellent reference and a full documented implementation at the bottom of this thread , also on SO How do I read data from serial port in Linux using C?
A simple fopen doesn't setup any of the serial ports communication parameters. You need to set the baud rate, number of bits, parity, and number of stop bits. And, if you want to use the linux line discipline or not. The termio structure is used to do this.
There are a couple good tutorial on how to use serial between linux and arduinos.
http://chrisheydrick.com/2012/06/12/how-to-read-serial-data-from-an-arduino-in-linux-with-c-part-1/
http://todbot.com/blog/2006/12/06/arduino-serial-c-code-to-talk-to-arduino/
I'm trying to communicate between Arduino Mega Adk (ADK 2011) and android device.
Something goes ok, but something goes completely wrong.
Transfer data from Android to Arduino via acc.read from Arduino side works fine.
But when i try to send some bytes from Arduino to Android - something strange happens.
First of all here is Arduino sketch:
#include <Max3421e_constants.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
#define COMMAND_LED 0x2
#define TARGET_PIN_18 0x12
#define TARGET_PIN_19 0x13
#define V_ON 0x1
#define V_OFF 0x0
#define PIN_18 18
#define PIN_19 19
#define INPUT_PIN 30
AndroidAccessory acc("Google, Inc.",
"DemoKit",
"Ololo device board",
"1.0",
"http://www.android.com",
"0000000012345678");
byte rcvmsg[3];
byte sndmsg[3];
int buttonState = 0;
void setup();
void loop();
void led_setup(){
pinMode(PIN_18, OUTPUT);
pinMode(PIN_19, OUTPUT);
pinMode(INPUT_PIN, INPUT);
}
void setup()
{
Serial.begin(115200);
Serial.print("\r\nStart");
led_setup();
acc.powerOn();
}
void loop()
{
if (acc.isConnected()) {
buttonState = digitalRead(INPUT_PIN);
if (buttonState == 1){
sndmsg[0] = 0x2;
sndmsg[1] = 0x1;
sndmsg[2] = 0x1;
int len = acc.write(sndmsg, 3);
digitalWrite(PIN_19, HIGH);
}
else {
//Nothing here for test
}
}
//usefull test for button
buttonState = digitalRead(INPUT_PIN);
if (buttonState == 1){
digitalWrite(PIN_19, HIGH);
}
else {
digitalWrite(PIN_19, LOW);
}
}
Ok. When acc.write() is executed it takes up to ~1 second to transfer data to android. And this time doesn't depend on number of bytes in sndmsg. Only if i execute acc.write(sndmsg,0) (sending 0 bytes) - everything goes fast.
That is a little bit disturbing. I've tried to change board to another one but have got the same result.
Any advices? may be that is a common bug, but there is no such much information in web.
UPD:
Wrote some very simple code, that only sends 3 bytes via acc.write.
here it is:
#include <Max3421e_constants.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
AndroidAccessory acc("Google, Inc.",
"DemoKit",
"Demokit board",
"1.0",
"http://www.android.com",
"0000000012345678");
byte msg[3];
unsigned long time;
void setup();
void loop();
void led_setup(){
}
void setup()
{
Serial.begin(115200);
Serial.print("\r\nStart");
acc.powerOn();
}
void loop()
{
if (acc.isConnected()) {
Serial.print("\r\nis Connected");
msg[0] = 0x1;
msg[1] = 0x1;
msg[2] = 0x1;
//Serial.print("\r\nSending");
time = millis();
Serial.print ("\r\nBefore write\r\n");
Serial.print (time);
acc.write(msg, 3);
time = millis();
Serial.print("\r\nAfter write: \r\n");
Serial.print (time);
//delay(500);
}
}
And it's debug output is:
is Connected
Before write
6983
After write:
10958
is Connected
Before write
10958
After write:
14491
is Connected
and so on. So on some reasons acc.write takes a lot of time and there is no data in the android app.
New UPD (19.01.2015):
Today i've performed some experiments. Here are results.
First, i've looked into AndroidAccessory.cpp and found write function:
int AndroidAccessory::write(void *buff, int len)
{
usb.outTransfer(1, out, len, (char *)buff);
return len;
}
Ok, then i looked into usb host shield library and found there usb.cpp with outTransfer fucntion, that returns error code if ouccured and 0x00 if everything is ok.
So i modified write function to return an error code instead of lenght, like this:
int AndroidAccessory::write(void *buff, int len)
{
byte rcode;
rcode = usb.outTransfer(1, out, len, (char *)buff);
return int(rcode);
}
and recived "4" as result.
According to MAX3421Econstants.h it is hrNAK (0x04) error code.
Any ideas? Looks like accessory does not recive NAKs from Android and write fails as a result.
Situation update:
Did some research. There is a hell of NAK's when accessory is connected. Here is dump from usb connector:
i found the solution. And it is very simple - i didn't setup communication with accessory correctly.
This is not an Arduino problem. Arduino works fine.
It is just how android interacts with android accessory.
So, results:
When AndroidAccessory is plugged to Android and Android haven't setup
communication with the accessory yet, Android OS will send a lot of
USB NAKs to the accessory and this is normal.
You must be careful
during setuping communication with the accessory. If you make some
mistakes, you can receive same situation: Probably possible to write
to the accessory, but accessory isn't possible to write to the
android.
If UsbManager opens accessory correctly, it stops sending
NAKs and starts recieve data from arduino.
It is a little bit strange for me, because it was really hard to found a problem: i have an application, written according to this manual: http://developer.android.com/guide/topics/connectivity/usb/accessory.html But, because i'm not very familiar with android, it seems that i've done some mistakes and receive strange behavior:
i was able to write to arduino
i was able to retrive information about arduino as android accessory
it was possible to ask for permissions
but when arduino tries to write to android, it recievs a lot of NAKs
So i decided to rewrite program in more simple way, just with one function and tried to do it in right way. And after some debugging it finally started to work as i want.
So thank everyone, who spend time for reading this.
Bonus: dump of normal packet, ended with EOP not NAK
UPD 26.01.2015:
I found problem and it was in my android code.
here is explanation:
Android developer's manual said that function, which set up communication with accessory must start it's own thread in which all communications with input and output streams are held. Smth like this:
private void openAccessory() {
Log.d(TAG, "openAccessory: " + accessory);
mFileDescriptor = mUsbManager.openAccessory(mAccessory);
if (mFileDescriptor != null) {
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(null, this, "AccessoryThread");
thread.start();
}
}
I really messed this thing up. Forgot about creating new thread in openAccessory function and tried to do it in different place. And recieve a hell of NAK's. Then i've changed my code and add some debug-like run() function like this:
public void run() {
final byte[] buffer = new byte[16384];
int ret = 0;
int i = 0;
while (i<50) {
try {
ret = mInputStream.read(buffer);
i++;
Thread.sleep(500);
} catch (IOException e) {
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And until this run method exists (while i < 50) android reads arduino correctly. And when thread ends up (i > 50) - Arduino starts to readout Error Code 4 (NAK) from Android.
That's all folks.
I'm trying to start a connection from my Arduino Mega ADK to my Android but I keep getting the error below whenever I try to acc.powerOn()
Error: OSCOKIRQ failed to assert
This is the firmware that I'm trying to run:
#include <Wire.h>
#include <Servo.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
int led = 13;
int EnableMotors = 22;
int Motor1FW = 24;
int Motor1RW = 26;
int Motor2FW = 28;
int Motor2RW = 30;
AndroidAccessory acc("FRBB",
"UgvBr",
"DemoKit Arduino Board",
"1.0",
"http://www.android.com",
"0000000012345678");
// the setup routine runs once when you press reset:
void setup() {
// Setting Serial at 115200 bps
Serial.begin(115200);
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
// Set up motor configs
pinMode(EnableMotors, OUTPUT);
pinMode(Motor1FW, OUTPUT);
pinMode(Motor1RW, OUTPUT);
pinMode(Motor2FW, OUTPUT);
pinMode(Motor2RW, OUTPUT);
// Powering the accessory
acc.powerOn(); ///// <<<<<<<<<<< ERROR
}
// the loop routine runs over and over again forever:
void loop() {
if(acc.isConnected()){
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
digitalWrite(EnableMotors, HIGH);
digitalWrite(Motor1FW, HIGH);
digitalWrite(Motor2FW, HIGH);
delay(2000);
digitalWrite(led, LOW); // turn the LED on (HIGH is the voltage level)
digitalWrite(EnableMotors, LOW);
digitalWrite(Motor1FW, LOW);
digitalWrite(Motor2FW, LOW);
delay(2000);
}
}
I've been looking everywhere and I couldn't find a solution to this problem yet. I also tried the DemoKit with Arduino.app on 1.0.1, but still the same issue. I'm developing it using Mac, but I don't think that it is a problem.
For testing purposes, I uploaded a code to blink the LED, and it worked just fine.
Spent a good 8 hours having the exact same problem. Seems like the Max3421e.cpp is faulty. Try replacing:
boolean MAX3421E::reset()
{
byte tmp = 0;
regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator
regWr( rUSBCTL, 0x00 ); //Remove the reset
while(!(regRd( rUSBIRQ ) & bmOSCOKIRQ )) { //wait until the PLL is stable
tmp++; //timeout after 256 attempts
if( tmp == 0 ) {
return( false );
}
}
return( true );
}
with
boolean MAX3421E::reset()
{
regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator
regWr( rUSBCTL, 0x00 ); //Remove the reset
while(!(regRd(rUSBIRQ) & bmOSCOKIRQ)) ;
}
In Max3421e.cpp located in the USB_Host_Shield library (in your Arduino IDE library folder).
Basically the change does not allow an exit until the PLL is really stabilized.
Worked for me at least, good luck
(Original hints and more about the fix here: http://arduino.cc/forum/index.php?topic=68205.0)
Use USB_Host_Shield_2.0 library with Arduino Mega ADK.
https://github.com/felis/USB_Host_Shield_2.0
IMPORTANT!!!
To use this library with the official Arduino ADK uncomment the following line in avrpins.h:
#define BOARD_MEGA_ADK
"OSCOKIRQ failed to assert" generally happens when the Max IC inside the board is not working properly. This can happen in two scenarios
The Maxim IC is not getting enough power. (In this case, try connecting an external power source to your board)
There is some problem in the circuit around Maxim IC. If this is the case, then you might have to replace the board.
So first try connecting an external power source and see if this solves it. Otherwise you might have to replace the board.
Super simple for me (with the same issue), just add a delay before acc.powerOn()
the example I saw added 100, but I decided boot up is fast enough for 500. i.e.
void setup()
{
// set communiation speed
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
delay(500);
acc.powerOn();
}