Arduino HM-10 Bluetooth with iOS : Connected, but it doesn't send values

171 views Asked by At

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

0

There are 0 answers