My current code is:
#IBAction func sendData(sender: UISwitch) {
if advertisingSwitch.on {
var parameter = NSInteger(45)
let data = NSData(bytes: ¶meter, length: 1)
if let connectedPeripheral = discoveredPeripheral {
println("========= In connected peripheral \(connectedPeripheral)")
//println("========= Send data is \(currentSendData)")
println("========= Characteristic is \(sendDataCharacteristic)")
println("========= data length is \(data.bytes)")
self.sendDataToCentral(connectedPeripheral, characteristic: sendDataCharacteristic!, data: data)
}
}
}
private func sendDataToCentral(peripheral: CBPeripheral, characteristic: CBCharacteristic, data: NSData) {
println("data is \(data)")
peripheral.writeValue(data, forCharacteristic: characteristic, type: CBCharacteristicWriteType.WithoutResponse)
println("writed characteristic \(characteristic)")
}
When I checked the Peripheral, it is connected showing:
BPeripheral: 0x1700ee980, identifier = E2377588-84CB-87ED-570A-B51614287B3C, name = TAv22u-FDF1, state = connected
The characteristic is getting from service scan with known UUID. I am sure the characteristic I got has function "write", which is
<CBCharacteristic: 0x174086090, UUID = FFE9, properties = 0x8, value = (null), notifying = NO>
after I executing function:
peripheral.writeValue(data, forCharacteristic: characteristic, type: CBCharacteristicWriteType.WithoutResponse)
The value in characteristic is not changing. I don't know where did I get wrong.
peripheral.writeValue(data, forCharacteristic: characteristic, type:
CBCharacteristicWriteType.WithResponse)
try .withResponse and check what is response from peripheral.
Related
I'm trying to get a peripheral to send a response each time my central does the .writeValue command. But it will only send it once.
didConnect
didDiscoverServices
didDiscoverCharacteristicsFor ...
// Enable notify from control characteristic:
for characteristic in serviceCharacteristics where characteristic.uuid == My_sensor_service.sensor_control_characteristicUUID
{
// ...
sensor_control_CBPeripheral = peripheral
sensor_control_CBCharacteristic = characteristic
sensor_control_CBPeripheral!.setNotifyValue(true, for: sensor_control_CBCharacteristic! )
//...
}
A few seconds later...
didUpdateValueFor My_sensor_service.sensor_notification_characteristicUUID ...
// Tell peripheral to send data:
sensor_control_CBPeripheral!.writeValue( command_data, for: sensor_control_CBCharacteristic!, type: .withResponse )
A few seconds later...
didUpdateValueFor My_sensor_service.sensor_control_characteristicUUID
let data = characteristic.value! // got correct data
A few seconds later...
didUpdateValueFor My_sensor_service.sensor_notification_characteristicUUID ...
// Tell peripheral to send more data:
sensor_control_CBPeripheral!.writeValue( command_data, for: sensor_control_CBCharacteristic!, type: .withResponse )
...but, I never get another:
didUpdateValueFor My_sensor_service.sensor_control_characteristicUUID
Peripheral just keeps sending...
didUpdateValueFor My_sensor_service.sensor_notification_characteristicUUID ...
I run this code on an iPad to create virtual BLE peripheral.
It starts advertising.
I run the central on iPhone.
Central detects peripheral and connects and subscribes.
Peripheral log unexpectedly has "Optional" in the log, though it's not in stringFromData.
IMAGE SHOWS stringFromData CONTENT AND LOG.........
class PeripheralViewController: UIViewController {
var packet_to_send = Data()
. . .
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
os_log("Central subscribed to characteristic")
// Init 1st sim packet:
packet_to_send = ("antenna data chunk " + String( packet_number )).data(using: .utf8)!
let stringFromData = String(data: packet_to_send, encoding: .utf8)
os_log("initial packet_to_send %d bytes = '%s'.", packet_to_send.count, String( describing: stringFromData))
stringFromData is an Optional. When you use String(describing:) to get the description of an Optional, it will be "Optional(yourDescription)" rather than "yourDescription".
You can avoid this by converting the Optional<String> into a String using optional binding or by providing a default value.
let stringFromData = String(data: packet_to_send, encoding: .utf8) ?? ""
os_log("initial packet_to_send %d bytes = '%s'.", packet_to_send.count, stringFromData)
I have a paired bluetooth peripheral which I have to send some credentials in a JSON like as follows
{"SSID":"WIFI_SSID", "Password": "WIFI_PASSWORD"}
And after the information has been sent the peripheral should connect to the provided WiFi credentials but I'm not completely sure the process is being performed correctly.
As soon the bluetooth peripheral has connected I start the process,
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
// As soon as the device has connected
peripheral.delegate = self
// Only discover the service I know it's for writing
peripheral.discoverServices([SERVICE_UUID])
}
The discoverServices will call the peripheral(:didDiscoverServices error)
func peripheral( _ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services! {
peripheral.discoverCharacteristics(nil, for: service)
}
}
Calling the following method where I do all the logic
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for characteristic in service.characteristics! {
let characteristic = characteristic as CBCharacteristic
debugPrint(characteristic.properties)
// This prints the following properties, reading + writing
// __C.CBCharacteristicProperties(rawValue: 10)
if characteristic.uuid.isEqual(RX_UUID) {
do {
let msgDictionary = ["SSID": wiFiCredentials.SSID, "Password": wiFiCredentials.Password]
let jsonData = try JSONSerialization.data(withJSONObject: msgDictionary,options:[])
peripheral.writeValue(jsonData, for: characteristic, type: CBCharacteristicWriteType.withResponse)
} catch let error as NSError {
debugPrint("Error in auth message JSON: \(error.description)")
}
}
}
}
Up to this point I think everything it's correct. After calling writeValue and setting the type to CBCharacteristicWriteType.withResponse I should expect something in the peripheral(:didWriteValueFor characteristic: error) method. What I receive in that method is the next error
Error Domain=CBATTErrorDomain Code=3 \"Writing is not permitted.\" UserInfo={NSLocalizedDescription=Writing is not permitted.}"
What I guess is that when I write the JSON value I shouldn't use the .withResponse flag and use .withoutResponse. If I do so I get the following log in the console.
[CoreBluetooth] WARNING: Characteristic <CBCharacteristic: 0x28388a040, UUID = 3E9D2532-2F00-11E9-9602-A44CC81C989A, properties = 0xA, value = (null), notifying = NO> does not specify the "Write Without Response" property - ignoring response-less write
Which confirms to me that I have to use the .writeWithResponse.
Is there something I am missing in the process? The JSON has to be sent using GATT and AFAIK this is the correct approach to do it. Are the printed CBCharacteristicProperties correct?
Things I've done:
The JSON is not the problem. I've tried writing a random variable "1".data(using: .ascii) and still receive the same error.
I tried to make an app that sends messages from iPhone to Bluetooth LE module. But for some reason, it gives the following error:
NSLocalizedDescription=Writing is not permitted.
Even though the types of the blePeripheral and the blePeripheral!.write are CBCharacteristicWrite.withResponse, the error says that writing is not permitted. How come the following code does not work for me?
func writeValue(data: String) {
let valueString = (data as NSString).data(using: String.Encoding.utf8.rawValue)
//change the "data" to valueString
if let blePeripheral = blePeripheral {
if let txCharacteristic = txCharacteristic {
blePeripheral.writeValue(valueString!, for: txCharacteristic, type: CBCharacteristicWriteType.withResponse)
}
}
}
func writeCharacteristic(val: Int8) {
var val = val
let ns = NSData(bytes: &val, length: MemoryLayout<Int8>.size)
blePeripheral!.writeValue(ns as Data, for: txCharacteristic!, type: CBCharacteristicWriteType.withResponse)
}
The resource where I found the code is:
https://learn.adafruit.com/crack-the-code/communication
I am trying to make two programs that run on separate devices communicate with each other over bluetooth with CoreBluetooth. I can find and connect peripherals from the manager, and I can browse services in connected peripherals, but when I try and try and discover characteristics, I get the error The specified UUID is not allowed for this operation. and as expected the service's characteristics come up nil.
What is this supposed to mean? I have tried to discover characteristics with specifying the UUID of the target and without, both show this error.
this is the function that prints the error.
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print(error.localizedDescription)//prints "The specified UUID is not allowed for this operation."
if service.characteristics != nil {
for characteristic in service.characteristics! {
if characteristic.uuid == CBUUID(string: "A4389A32-90D2-402F-A3DF-47996E123DC1") {
print("characteristic found")
peripheral.readValue(for: characteristic)
}
}
}
}
this is where I look for peripherals.
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if peripheral.services != nil {
for service in peripheral.services! {
if service.uuid == CBUUID(string: "dc495108-adce-4915-942d-bfc19cea923f") {
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
}
this is how I add the service characteristic on the other device.
service = CBMutableService(type: CBUUID(string:"dc495108-adce-4915-942d-bfc19cea923f"), primary: true)
characteristic = CBMutableCharacteristic(type: CBUUID(string: "A4389A32-90D2-402F-A3DF-47996E123DC1"), properties: .write, value: nil, permissions: .writeable)
service.characteristics = [characteristic]
I tried a number of different combinations of properties and permissions (including .read/.readable) and I get the same error.
You are attempting to read the value of a characteristic that you have set as write-only, so Core Bluetooth gives you an error; the read operation is not valid for the specified characteristic.
If you want your characteristic to be both readable and writable you need to specify this:
service = CBMutableService(type: CBUUID(string:"dc495108-adce-4915-942d-bfc19cea923f"), primary: true)
let characteristic = CBMutableCharacteristic(type: CBUUID(string: "A4389A32-90D2-402F-A3DF-47996E123DC1"), properties: [.write, .read], value: nil, permissions: [.writeable, .readable])
service.characteristics = [characteristic]