Arduino HM-10 Bluetooth with iOS : Connected, but it doesn't send values
Cyan
Posted on July 24, 2023
I'm trying to make an iOS (SwiftUI based) app to connect the arduino and send the current latitude value of ios to arduino. I successfully made the view that allow user to select the bluetooth device, and the UUID/name of the device is successfully displayed. Also, the arduino device detects connection (I used LiquidCrystal to display serial and it says "OK+CONN" and "OK+LOST" if connection was lost.), but when I click "fetch location" button, nothing happens on arduino side.
Also, when I click select device, it automatically navigates to mainview(), and I can't figure why.. (This is less important than the bluetooth problem...)
For your information, I'll attach my frontend and backend codes.
ConnectView.swift
import SwiftUI
import CoreBluetooth
import Awesome
struct ConnectView: View {
@State private var isDeviceSelectionPresented = false
@State private var selectedDevice: CBPeripheral?
@State private var isSendingData = false
private var writeType: CBCharacteristicWriteType = .withoutResponse
@StateObject private var bleManager = BLEManager()
@StateObject private var locationDelegate = LocationDelegate()
private var peripherals: [CBPeripheral] { bleManager.peripherals }
private var txCharacteristic: CBCharacteristic?
weak var writeCharacteristic: CBCharacteristic?
var body: some View {
NavigationView {
VStack(spacing: 20) {
HeadView(headTitle: "Cydial 장치 연결하기")
Button(action: {
isDeviceSelectionPresented = true
}) {
ZStack{
RoundedRectangle(cornerRadius: 8)
.stroke(Color.accentColor, lineWidth:2)
.frame(height:40)
HStack(spacing:10){
Image(systemName:"checkmark")
Text("Select Device")
.fontWeight(.semibold)
}
}
}
.sheet(isPresented: $isDeviceSelectionPresented) {
DeviceSelectionView(selectedDevice: $selectedDevice, isPresented: $isDeviceSelectionPresented)
.environmentObject(bleManager)
}
if let connectedDevice = bleManager.connectedPeripheral {
VStack(alignment:.leading ,spacing: 5) {
HStack{
Image(systemName:"checkmark.circle")
Text("Device Connected")
}
.font(.title3)
.fontWeight(.semibold)
Text("Device Name: \(connectedDevice.name ?? "Unknown")")
Text("UUID: \(connectedDevice.identifier.uuidString)")
}
.padding(.top, 10)
}
HStack{
Image(systemName:"location.circle")
Text("Current Latitude: \(locationDelegate.latitudeValue)")
Spacer()
}
Button(action: {
// sendMessageToDevice("\(locationDelegate.latitudeValue)")
sendDataToArduino()
}) {
ZStack{
RoundedRectangle(cornerRadius: 8)
.stroke(Color.accentColor, lineWidth:2)
.frame(height:40)
HStack(spacing:10){
Image(systemName:"rectangle.portrait.and.arrow.forward")
Text("Fetch Location")
.fontWeight(.semibold)
}
}
}
Spacer()
}
.padding()
}
}
func sendDataToArduino() {
guard let peripheral = selectedDevice,
let txCharacteristic = txCharacteristic,
let dataToSend = "\(locationDelegate.latitudeValue)".data(using: .utf8) else {
print("Error: Bluetooth is not ready.")
return
}
isSendingData = true
selectedDevice?.writeValue(dataToSend, for: txCharacteristic, type: writeType)
}
func sendMessageToDevice(_ message: String) {
if let data = message.data(using: String.Encoding.utf8) {
selectedDevice!.writeValue(data, for: writeCharacteristic!, type: writeType)
}
}
// func sendBytesToDevice(_ bytes: [UInt8]) {
// let data = Data(bytes: UnsafePointer<UInt8>(bytes), count: bytes.count)
// selectedDevice!.writeValue(data, for: writeCharacteristic!, type: writeType)
// }
// func floatToUInt8(_ value: Float) -> UInt8? {
// // Check if the value is within the valid range for UInt8
// let max = (UInt32(UInt16.max) + 1) * UInt32(UInt32(UInt8.max) + 1) - 1
// let int = UInt32(((self / maxRange + 1.0) / 2.0 * Float(max)).rounded())
// let a = int.quotientAndRemainder(dividingBy: UInt32(UInt16.max) + 1)
// let b = a.remainder.quotientAndRemainder(dividingBy: UInt32(UInt8.max) + 1)
// return [UInt8(a.quotient), UInt8(b.quotient), UInt8(b.remainder), 0]
// }
}
struct ConnectView_Previews: PreviewProvider {
static var previews: some View {
ConnectView()
}
}
DeviceSelectionView.swift
import SwiftUI
import CoreBluetooth
struct DeviceSelectionView: View {
@Binding var selectedDevice: CBPeripheral?
@EnvironmentObject var bleManager: BLEManager
@Binding var isPresented: Bool
var body: some View {
List(bleManager.peripherals, id: \.self) { peripheral in
Button(action: {
bleManager.connectToDevice(peripheral)
isPresented = false
}) {
Text(peripheral.name ?? "Unknown Device")
}
}
.onAppear {
bleManager.startScanning()
}
.onDisappear {
bleManager.stopScanning()
}
.onChange(of: bleManager.connectedPeripheral) { connectedPeripheral in
if let selectedDevice = selectedDevice, selectedDevice == connectedPeripheral {
isPresented = false
}
}
}
}
struct DeviceSelectionView_Previews: PreviewProvider {
static var previews: some View {
DeviceSelectionView(selectedDevice: .constant(nil), isPresented: .constant(true))
.environmentObject(BLEManager())
}
}
BLEManager.swift
import Foundation
import CoreBluetooth
import CoreLocation
class LocationDelegate: NSObject, ObservableObject, CLLocationManagerDelegate {
@Published var latitudeValue: Float = 0.0
private let locationManager = CLLocationManager()
override init() {
super.init()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
latitudeValue = Float(location.coordinate.latitude)
}
}
}
class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate {
var centralManager: CBCentralManager!
@Published var peripherals: [CBPeripheral] = []
@Published var connectedPeripheral: CBPeripheral?
@Published var txCharacteristic: CBCharacteristic?
override init() {
super.init()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func startScanning() {
centralManager.scanForPeripherals(withServices: nil, options: nil)
}
func stopScanning() {
centralManager.stopScan()
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
startScanning()
} else {
print("Error: Bluetooth is not available.")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if !peripherals.contains(peripheral) {
peripherals.append(peripheral)
}
}
func connectToDevice(_ peripheral: CBPeripheral) {
connectedPeripheral = peripheral
centralManager.connect(peripheral, options: nil)
}
func disconnectFromDevice() {
if let peripheral = connectedPeripheral {
centralManager.cancelPeripheralConnection(peripheral)
connectedPeripheral = nil
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices(nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let services = peripheral.services {
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let characteristics = service.characteristics {
for characteristic in characteristics {
if characteristic.properties.contains(.write) {
txCharacteristic = characteristic
}
}
}
}
}
I tried to port UIKit based example project to this, but it doesn't work: Question
Posted on July 24, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.