I have a hidden service/characteristic on a BLE device, that only becomes visible if you send the "right" command to another characteristic. However, if I stay connected, and just call "discoverServices:nil" or "discoverServices:service-i-care-about", it won't find it once enabled.
I changed my firmware to make the device not hide the service on disconnection (which is what I would want), but to stick around, and I know the service is getting enabled, because I can reconnect to device, and the service shows up.
I don't want to do this, because the whole point of hiding the service is you have to send the right command to enable the service (for the record, it is a firmware update service provided by a MCU vendor, so I can't change the service to be one of "mine" or put any security around the service itself)
Is this the intended bluetooth behavior? Or is iOS perhaps caching something and I have to do something to make it not get the cached values?
iOS caches any discovered peripheral and the corresponding services and characteristics for performance reasons. If you need to change the GATT table of your peripheral at any given time you have two options to tell the centrals:
tell the central via the Services Changed characteristic
change the mac address of your peripheral (not recommended but some chipset makers use this workaround, e.g., NordicSemi in the BLE bootloader)
We came across this problem as well because we need to hide the firmware update service of our embedded device until we jump to the bootloader.
Related
I am developing a web application which shows the status of the all available smart devices in my hub. and I can also control the devices from this application.
For example, if I want to turn on the switch I send "on" commands with appropriate contexts to smartthings API.
In order the send commands, the devices should be active (it should respond to commands).
And I got the state of the device through API call (device.status) but this state found with the device object is not accurate.
For example, the Econet valve is actually responding to my commands.but it states shows INACTIVE.
So I can't trust on the values get from "device.status" parameter. is there any other approach?
Update: In order to know the current value of devices and take actions according to the current value, we need to know whether the device is responding or not. Currently, we cannot rely on the device status like ACTIVE, ONLINE because even after disconnecting the devices from networks the states doesn't change.
I have two BLE devices with the same UUID. Is there any way to connect to both of them so that they are both connected at the same time?
Right now I'm not able to even see both devices simultaneously using a bluetooth explorer, so I assume for the system they appear as just one device. Is it still somehow possible?
I assume that with UUID you mean the MAC-Address (Bluetooth address) of the device. UUIDs are typically used for services and characteristics.
All connection procedures work with the Bluetooth address as the main parameter. So two devices with the same address will be treated as the same device. (In fact, it is a common requirement that MAC-Addresses of Bluetooth devices should be unique, exactly for this reason.)
So it is not possible to connect to two devices with the same address at the same time. (*)
You can find more information about how connection is done in the Bluetooth Core Spec, Vol. 3, Part C, chapter 9.3.5 - 9.3.8.
(*) This is meant in the common way of having a connection to two different devices. Since incoming messages are not distinguishable on Link Layer level between the two devices with identical address (your control will always think there is only one device with the given address out there), you could mess around with this fact, especially in non-encrypted connections (since encryption is negotiated on a device-to-device basis, another device could not join in an encrypted connection, even if it has the same Bluetooth address). But it is definitely not recommended to do so.
If two devices are having the same UUID , then I think they would be consider as a single device. What I would suggest , send a trigger notification to the UUID and check which device will respond first . Secondly , try to send notification to devices put them far apart . The nearer to your smartphone/bluetooth explorer , will get notify first . Bluetooth works on the distance basis, the device which is near to the source will get the notification than the other one.I tried the same with Beacons but end up like you.
iOS 6 supposedly caches the discovered services and characteristics of peripherals so that reconnecting to known peripherals is faster. However, it doesn't seem to work in my app.
I save a peripheral after connecting to it, and on the reconnect I call retrievePeripherals with the saved peripheral's UUID. My didRetrievePeripherals gets called and I connect to the peripheral. My didConnectPeripheral gets called and I call discoverServices. I was expecting the services to be returned to my app from the cache. However, the service tables are read from my peripheral.
Because my app is busy reading the service tables, I miss the first measurement sent from the peripheral.
Does anyone know why the cache is not being read? Is there some option I need to set somewhere?
You should try to encrypt the connection. Encrypted connections require pairing and after that, the caching is truly turned on. Plain connections not necessarily trigger the caching mechanism and there is no official statement on this. You should also try iOS beta to see if this has changed there. ;)
The other thing you should consider is optimizing the service discovery. If measurement is very important, then discover the characteristics for that first and once that is done, continue on with the others.
Sorry for the long title, but we are having a pretty interesting issue with using corebluetooth for ios. We are issuing a call to retrievePeripherals in CBCentralManager and are able to find the previously paired device.
This happens though regardless if the device is on or off though. I can't find anything in apple's documentation as to why it's able to find the device when it is off though and it isn't showing up in Settings -> Bluetooth -> Devices. I'm suspecting that Apple is caching this information but can't find any documentation to confirm this. Also, when the device is off and we issue the connect call, the program continues to execute as normal but the delegate for didFailToConnect never gets called. When the device is turned on, it will connect immediately.
Is there a way to pass a timeout parameter when trying to connect to a device? If not, what would the best solution be to handling reconnecting to a previously used device for an application (we're storing the last connected device within the app).
Two points you need to know about retrievePeripherals: and connectPeripheral:
1.) retrievePeripherals: attempts to retrieve the CBPeripheral object associated with the uuid you supply. Even if the ble device is off (or on the other side of the country) retrievePeripherals: will still return an instance of CBPeripheral that you can call connectPeripheral: on. This is done intentionally so that you can issue a call to a peripheral that is not even around and still automatically connect to it when it comes back into range. It basically creates a marker inside the system bluetooth so that when the device is actually seen, it will know it should connect to it.
2.)connectPeripheral: will not time out unless the communication channel is broken with the actual device. If the iOS device has not seen the device, it will not fail and should not time out (unless some error occurs inside the system bluetooth).
And as for the timeout parameter, there is no documented way inside the CoreBluetooth framework. You can create your own implementation for it, however I believe you'd be better off keeping a list of which peripheral uuid's you've actually called connectPeripheral: on and then just pop them from the list when they connect. If you no longer want to connect to a peripheral in the list call cancelPeripheral: on that UUID, call connectPeripheral: on the other, and swap entries. Good to go.
I've looked everywhere and tried everything, but nothing seems to work :(
On iOS, I'm making an app (for iOS 6 and above) in which iOS devices need to exchange data. Therefore, both devices need to be peripheral and central at the same time. I've done exactly as specified in the WWDC video, but the devices can't connect successfully with each other.
When I make one device only central and the other only peripheral, the central connects seamlessly to the peripheral.
However, when both devices are peripheral and central at the same time, I get random errors: at any stage (discovering services/characteristics or setting notify value to YES) errors sometimes happen, and sometimes discoverServices doesn't even call didDiscoverServices
Is there something different I should be doing? I simply merged the peripheral and central code into one view controller. I've noticed that if device "a" connects to device "b", and then device "b" connects to device "a", it works more often than not. I manage this by using NSThread sleepForTimeInterval: manually for different amounts of time on each device, but how could I get one device to connect first (and then the other) in a reliable (and not manually pre-defined) way?
If I do get errors, usually they're simply Unknown error
Please let me know if you need any code or any other information :)
Yes, it can be in both roles at the same time. You just have to initialize a CBPeripheralManager and a CBCentralManager. As soon as the peripheral manager is initialized and you receive the POWER ON state the device starts acting as a peripheral. You can add your services at this point and receive connections from other devices. At the same time you can use the central manager to scan and initiate connections to other peripherals.
Note that you cannot connect to your own device even if it acts as a peripheral.
For your errors, I suggest:
Turn off scanning before initiating a connection. That is, scan, find peripheral, stop scan, connect. Connection and scanning do not like each other.
Use a dedicated queue for handling bluetooth events, not the main queue. [[CBCentralManager alloc] initWithDelegate:self queue:my_dedicated_bluetooth_q]
Unfortunately, the stack sometimes become unstable. Even restarts are possible. But this usually happens only under heavy loads or several simultaneous connections. Hopefully, this will be improved in iOS7.
The unfamous Unknown error started to appear for several developers recently. Judging from your description there are probably a number of reasons why your setup may fail and it would require much more info that what fits well into a SO question.
For more info I suggest you search the bluetooth-dev mailing list archives https://lists.apple.com/archives/Bluetooth-dev or send a mail Bluetooth-dev#lists.apple.com. The community provides great help if you approach with reasonable questions like this.
As per my understanding one device can work with one mode at a time . That is if the device is working in the peripheral mode then it you cant work it as a central mode .If you see some standard examples like BTLE transfer or lilke Light Blue those are working in one mode at a time .
Firstly, what do you mean "the same time"?
If you mean the device advertising to other devices while it scanning for other devices, it can not.
But you can create two threads which share same lock to advertising and scanning.
Before scanning, stop advertising, before advertising, stop scanning.
I tested on my iPhone 4s and iPad air, worked well.