Direct Bluetooth connection from App(No Particle Cloud)


#82

awesome @eric, just did a pull and I see it now. Thanks a million. I will play with this a bit.


#83

Hey @eric,

Things are going great an I have every intention of actually controlling some devices today!

I have one glitch though. I am writing some data to the module, then I am writing the footer command 0x03 0x04 but this is not ending the data. The module is hanging until the timeout and then acting on the data but also going into safe mode so I cannot send anything else until a power cycle. Your iOS app is working properly so I have been looking in there but am a little lost. I see you are doing alot in the didUpdateValueForCharacteristic function but not being experienced with Swift I am having a bit of a hard time determining what you are doing there.

Do I not just write my data then on a separate write send the 0x03 0x04 to end the stream? This is what I have now which hangs the module like it is not getting the end command:

- (IBAction)doIt:(id)sender{
    NSLog(@"connection state: %li", (long)self.bluzModule.state);
    if(self.bluzModule.state == CBPeripheralStateDisconnected){
        NSLog(@"Connecting");
        [_manager connectPeripheral:self.bluzModule options:nil];
    }
    NSLog(@"Sending data");
    NSData *dataStart = [NSData dataWithBytes:(unsigned char[]){0x03, 0x05, 0x06} length:3];
    NSData *dataEnd = [NSData dataWithBytes:(unsigned char[]){0x03, 0x04} length:2];
    [self.bluzModule writeValue:dataStart forCharacteristic:Tx type:CBCharacteristicWriteWithResponse];
    [self.bluzModule writeValue:dataEnd forCharacteristic:Tx type:CBCharacteristicWriteWithResponse];
    NSLog(@"Send Complete");
}

#84

Are you just sending data down and not up?

That looks correct. The didUpdateValueForCharacteristic function is mainly used to read values back from bluz, so if you aren’t sending from bluz to your app, it shouldn’t affect anything.

I do see that you are using type:CBCharacteristicWriteWithResponse. You can change that to type:CBCharacteristicWriteWithoutResponse. Bluz supports that, we had another product line that doesn’t and we use the same app for both, hence why we check.

What are you doing in the callback function? Could that be hanging bluz? Also, when are you sending data down, as soon as you connect? Or sometime after?


#85

Hi @eric,

Here is my application side on the Bluz module. I am never sending anything from the module to the app right now:

#include "application.h"

uint8_t bleBuffer[256];
int arrayIndex = 0;
int LED = D7;

void dataCallbackHandler(uint8_t *data, uint16_t length) {
	//Flash LED to indicate receive of data
	digitalWrite(LED, HIGH);
	//Return if the data is larger than our buffer and ignore data
	if(arrayIndex == 255 || length > 256){
		//Buffer full
		return;
	}
	//read data into our local buffer
   for(int i = 0; i < length; i++){
	   bleBuffer[arrayIndex] = data[i];
	   arrayIndex++;
   }
   //Turn LED back off
   digitalWrite(LED, LOW);
   return;
}

void setup() {
    pinMode(LED, OUTPUT);
    BLE.registerDataCallback(dataCallbackHandler);
    Serial1.begin(115200);
}

void loop() {
	//Check to see if there is data in the ble buffer
    if(arrayIndex != 0){
    	Serial1.println("got data: ");
    	//Print data out
    	for(int i = 0; i < arrayIndex; i++){
    		Serial1.print(bleBuffer[i]);
    	}
    	Serial.println();
    	//Clear bleBuffer
    	memset(bleBuffer, 0, arrayIndex);
    	//set array index back to 0
    	arrayIndex = 0;
    }
}

On the iOS app side I am not sending data to the module until the user presses a button so it is not immediate after connection. I updated the code to write without response but am getting the same. Also I threw in a 200mS delay between sending the data and the end of data command:

- (IBAction)doIt:(id)sender{
    NSLog(@"connection state: %li", (long)self.bluzModule.state);
    if(self.bluzModule.state == CBPeripheralStateDisconnected){
        NSLog(@"Connecting");
        [_manager connectPeripheral:self.bluzModule options:nil];
    }
    NSLog(@"Sending data");
    NSData *dataStart = [NSData dataWithBytes:(unsigned char[]){0x03, 0x05, 0x06} length:3];
    NSData *dataEnd = [NSData dataWithBytes:(unsigned char[]){0x03, 0x04} length:2];
    [self.bluzModule writeValue:dataStart forCharacteristic:Tx type:CBCharacteristicWriteWithoutResponse];
    [NSThread sleepForTimeInterval:0.2f];
    [self.bluzModule writeValue:dataEnd forCharacteristic:Tx type:CBCharacteristicWriteWithoutResponse];
    NSLog(@"Send Complete");
}

It’s coming along. I believe this is my last big hurdle. I should also mention that the modified version of your app that sends a 0x03 as the header is working properly. It is strictly my app.


#86

Hmmm… I am not sure. Is it possible for you to send me your entire app zipped up? I can try and take a look later today. Seems to be correct but perhaps there is an issue elsewhere.


#87

Zipped app available here:
https://drive.google.com/file/d/0B5fTLsGWqbCBOWlER0dGSDlueVU/view?usp=sharing


#88

Hey @eric,

I am still trying to track this down. Where in the Bluz module firmware does it receive that 0x03, 0x04 and interpret that as the end of the data? I need to debug on the Bluz side to see if it is getting my end of data. Your app is working but mine is not and not sure why but it seems like it is not getting my end of data packet for some reason. This seems to be the last hurdle.


#89

Yeah, sorry, I haven’t had a chance to look at your app code yet, I have been pretty bogged down with a few other items.


#90

Well, good news. That was not the problem. I put a line in there to turn on the D7 LED when 0x03, 0x04 is received and it turns on when I run my app so it is getting the eos. Now I just have to figure out why the module is hanging after that when using my app.

After I send my data and then eos the LED turns on but the application does not run for about 40 seconds, then it prints out my data and goes into safe mode(flashing magenta LED). Weird huh.


#91

I assume your app isn’t connecting to the cloud? That would probably cause issues. When the BLE connection is established, the firmware will go into a blocking thread while trying to connect to the Particle cloud. This will stop other code from executing for about 40 seconds.

I just added a quick work-around to this. If you get latest from the develop branch, you should have the fix. All you need to do is add the line:

SYSTEM_MODE(MANUAL);

To the top of your user code and it should basically not call the cloud connection portion. The LED will be green when advertising and then change to white when connected, but stay blinking in the same 2 second intervals. This should unblock your user code and your app should work.

NOTE: I haven’t fully tested this fix, so there may be an unforeseen issue I didn’t catch.


#92

WHOOOO

Thank you so much @eric It’s working now! I am able to send data to the module directly and my application is printing it out to the serial log. Time to have some fun now!

I have some good ideas for this and will definitely be doing a Hackster.io post on this very soon on our Hackster profile here:
https://www.hackster.io/ControlEverything/projects

I will be putting together an application to receive bytes over Bluetooth then output them to the I2C port to operate and monitor our devices. Should be pretty cool and will give users who have no network access in remote areas a way to still control devices via their smartphone/tablet/computer. People are always asking for a Bluetooth interface option and up until now we have not had a solution. I think Bluz will fit that bill nicely now.

Thanks again @eric
P.S. I would say this can be marked as Solved!


#93

Awesome, glad it’s working!

One more item we need to add to this is the ability to send data back to the app, but that should be relatively straight forward. Now that this is in the repo, it will certainly be in the next release and I will add documentation around all of it as well.

One limitation of this is that the cloud isn’t connected anymore, so firmware updates aren’t possible and someone would have to do them through serial (or do a factory reset to get back to cloud connection). Not 100% ideal. Part of the way to solve it is allow people to go back into AUTOMATIC mode or call something like Particle.connect(), I am not sure if those would work or not at this point. Eventually I would like to add the ability to flash code directly from the app, but that is definitely off in the future.

Lots of items to do!


#94

Hi @eric

I have a very rudimentary app put together but I am controlling a couple of relays. On the Bluz module firmware I take the command bytes in and then write them to the I2C port to drive relays connected to an MCP23008 IC. It’s working quite well. See short video here:

Using this architecture it’s possible to write a generic firmware into the module that takes commands in, writes them to the I2C port, then it can return data from the chip or just a simple AOK if the write command was successful. This means all commands for different devices can live in the iOS/Android app itself. This would allow us to make an app that would work with any device www.controleverything.com sells. I think this will go over very well.

Of course as you said the next step is to write data back to the app from the Bluz module as I only have 1 way communication right now so I cannot read the status of the relays or any other device for that matter.


#95

That’s awesome! Do you mind if I share that video on social media?

As for sending data back to the app, I just added support for it! If you get latest, you will see the updated custom_data_service app with the changes. So you simply need to call BLE.sendData() and it will append the header (basically just the byte that identifies the service) and send it back. So you don’t need to worry about appending the header on the bluz side, but you will need to check for it in your app. Anything with a header of 1 and 2 should be ignored.

Also, I did change the CUSTOM_DATA_SERVICE id from 3 to 4. The fact that our EOS buffer is 0x03, 0x04 means that someone could mess things up if they tried to send the byte 0x04 through this system. So instead of adding for 0x03 to your data in the app, you should change it to 0x04. Same when you check the data, check for 0x04. Sorry for the inconvenience on that, but I figure it is better to do it now before more people start using it.

One other note, the data you get in your data callback is in a high level interrupt, so you shouldn’t put any blocking code in there. You aren’t, so that’s fine, but you can see how I basically moved the BLE.sendData outside of that and put it into the main loop and triggered it with a flag. This way there is no chance of anything hanging in that main callback. If you put blocking code in there, it could interrupt the BLE functionality.

Let me know if you have any more issues or questions, I think now that you can send data back you should have everything you need!


#96

Sorry @eric

I just figured out the question I was about to ask.

Yes please do whatever you want with the video.

I do have successful two way communication now!!!


#97

Well done both. You guys are illustrating once again that a little persistence is what it takes.

I have a project I could switch to Bluz if I had this capability to communicate two-ways between bluz and my app (cordova-based) then the phone’s internet connection is down. I could travel the same journey as @IOTRav but would prefer to wait if an “official” version is on the way. @eric, are you still planning to do this? @IOTrav are you planning to put this in the bluz repo?

As to which of the two models - piggyback or separate characteristic - I can see advantages to both. In my application (mobile air quality) the internet connection on the phone comes up and down a lot. So a degree of independence between local connection and cloud connection feels like a good thing.

Thx for any suggestions.

PS. I guess @IOTRav’s solution does not encrypt the connection in the way that bluz does with the particle cloud. If so, I am thinking that it would be good to add that, at least as an option, so as to cater for applications where privacy is needed.


#98

This feature is currently in the latest release, 1.1.47, so you can certainly use it now. We have an example application setup that you can look at: https://github.com/bluzDK/bluzDK-firmware/blob/develop/user/applications/custom_data_service/custom_data_service.cpp

The only thing is that we haven’t added this to the docs yet. That was intentional as I would still call this a bit experimental, I haven’t had a chance to fully test. However, it has been used successfully so it should work just fine. If you can try it out and let me know it works, I will get the documentation in order.

The example I shared shows how to send and receive data from bluz. To handle it from the app side, you just send the data down but append a “header” of 0x04 to the data. The data needs to be sent in 20 byte chunks, which is a restriction of BLE, so you only append the 0x04 to the first chunk, not every one. When you are done transmitting all data, you send a two-byte packet of just [0x03, 0x04]. When you receive data back, you will get the same thing, 0x04 as the header and a final end of stream packet that is just [0x03, 0x04].

We use those headers to denote where the data goes in bluz. For example, a header of 0x01 means it is data meant for the cloud. A header of 0x02 is used to get info from bluz, like the device ID. So 0x04 is used for this mechanism. We can add more of these services later just by adding more headers, allowing us to piggy back on the one service/characteristic. Eventually we will also add the ability to add more services and characteristics as well.

Let me know if that all makes sense or to have any more questions. Thanks


#99

Hi @paul_tanner

I can attest to this working with the 1.1.47 latest release. I wrote an iOS native app for testing and I have good two way communication between the app and the controller.

I have done some development with Cordova but honestly never tried Bluetooth or Bluetooth 4.0 LE on it. If Cordova has support for Bluetooth 4.0 LE(Have not checked) then I see no reason why this will not work. It will need support for sending byte arrays since as @eric mentioned you need to send a header byte of 0x04 which is a Hex formatted byte. Sending raw byte arrays is not always something that is supported in high level development environments such as Cordova so you will need to check that. Sometimes they just give you a stream for sending and receiving strings.

Keep us updated. Would be great to have a Cordova sample app for this!


#100

Thx both. I will try this out as soon as I can. If/ when I get it working with cordova (using the excellent @randdusing’s plugin https://github.com/randdusing/cordova-plugin-bluetoothle) I will post something for others to try. I am reasonably confident because I’ve already built an app this way. And yes, raw byte arrays are what the plugin handles.


A Bluz bridge/gateway hybrid app using Phonegap (Cordova)?
#101

Definitely keep us updated!