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
Top comments (0)