ESP32 not able to send data to iOS app

I have written a code for iOS app which has multiple views. I have one set of bluetooth communication protocol. How can I combine these views to have only one set of bluetooth communication protocol? I am attaching the whole code below. I am not receiving the data from ESP32 but transmission from the app works well. I am completely new at this so please help me.

//
// ContentView.swift
//
//

import SwiftUI

struct ContentView: View {
// App Variables
@State private var angle0 = false
@State private var angle15 = false
@State private var angle45 = false
@State private var vibration = false
@State private var vibrationText = "OFF"
@State private var sound = false
@State private var soundText = "OFF"
@State private var light = false
@State private var lightText = "OFF"
@State private var negativeFeedback = false
@State private var negativeFeedbackText = "OFF"
@State private var blastMode = false
@State private var setAngle = -10
@State private var vibration1 = false
@State private var vibrationText1 = "OFF"
@State private var sound1 = false
@State private var soundText1 = "OFF"
@State private var light1 = false
@State private var lightText1 = "OFF"
@State private var negativeFeedback1 = false
@State private var negativeFeedbackText1 = "OFF"
@State private var blastMode1 = false
@State private var batSpeed = 0
@State private var currentView: Int = 0
@State private var Bunt = true
@State private var showingPopover = false
@State private var showingPopover1 = false
@State private var showingPopover2 = false
@State private var output:UInt16 = 0
@State private var batAngle:UInt16 = 0
@State private var batVelocity:UInt16 = 0

// Bluetooth Variables
var bluetooth = Bluetooth.shared
@State var presented: Bool = false
@State var list = [Bluetooth.Device]()
@State var isConnected: Bool = Bluetooth.shared.current != nil { didSet {
  if isConnected {
    presented.toggle()
  }
  else{
    angle45 = false
    angle0 = false
    angle15 = false
    light = false
    sound = false
    vibration = false
    blastMode = false
    negativeFeedback = false
    setAngle = -10
    vibrationText = "OFF"
    soundText = "OFF"
    lightText = "OFF"
    negativeFeedbackText = "OFF"
  }
} }

@State var response = Data() { didSet {
if (String(data: response, encoding: .utf8) == "49"){
angle0 = true
angle15 = false
angle45 = false
blastMode = false
setAngle = 0
}
else if (String(data: response, encoding: .utf8) == "50"){
angle15 = true
angle0 = false
angle45 = false
blastMode = false
setAngle = 15
}
else if (String(data: response, encoding: .utf8) == "51"){
angle45 = true
angle0 = false
angle15 = false
blastMode = false
setAngle = 45
}
else if (String(data: response, encoding: .utf8) == "54"){
light = true
lightText = "ON"
light1 = true
lightText1 = "ON"
}
else if (String(data: response, encoding: .utf8) == "55"){
light = false
lightText = "OFF"
light1 = false
lightText1 = "OFF"
}
else if (String(data: response, encoding: .utf8) == "56"){
negativeFeedback = true
negativeFeedbackText = "ON"
negativeFeedback1 = true
negativeFeedbackText = "ON"
}
else if (String(data: response, encoding: .utf8) == "57"){
negativeFeedback = false
negativeFeedbackText = "OFF"
negativeFeedback1 = false
negativeFeedbackText1 = "OFF"
}
else if (String(data: response, encoding: .utf8) == "97"){
vibration = true
vibrationText = "ON"
vibration1 = true
vibrationText1 = "ON"
}
else if (String(data: response, encoding: .utf8) == "98"){
vibration = false
vibrationText = "OFF"
vibration1 = false
vibrationText1 = "OFF"
}
else if (String(data: response, encoding: .utf8) == "52"){
sound = true
soundText = "ON"
sound1 = true
soundText1 = "ON"
}
else if (String(data: response, encoding: .utf8) == "53"){
sound = false
soundText = "OFF"
sound1 = true
soundText1 = "OFF"
}
else if (String(data: response, encoding: .utf8) == "l"){
blastMode = true
setAngle = -10
angle45 = false
angle0 = false
angle15 = false
light = false
sound = false
vibration = false
negativeFeedback = false
vibrationText = "OFF"
soundText = "OFF"
lightText = "OFF"
negativeFeedbackText = "OFF"
light1 = false
sound1 = false
vibration1 = false
negativeFeedback1 = false
vibrationText1 = "OFF"
soundText1 = "OFF"
lightText1 = "OFF"
negativeFeedbackText1 = "OFF"
}
else{
output = UInt16(String(data: response, encoding: .utf8) ?? "0") ?? 0
batAngle = output >> 8
batVelocity = output & 255
}
} }
@State var string: String = ""
@State var value: Float = 0
@State var state: Bool = false { didSet { bluetooth.send([UInt8(state.int)]) } }

@State var editing = false

var body: some View {

// let degreeOfFreedom = 5
ZStack{

            VStack{
                
                Button {
                    presented.toggle()
                } label: {
                    HStack {
                        Text("Connect to Bat")
                            .bold()
                        ZStack {
                            Image("bluetooth")
                                .resizable()
                                .foregroundColor(Color.black)
                                .frame(width: 30, height: 30)
                        }
                    }
                }
                .frame(width: UIScreen.screenWidth, height: 35)
                .background(Color.green)
                
                Group{
                Image("logo")
                    .resizable()
                    .scaledToFill()
                    .frame(width: 200, height: 80)
                    HStack (spacing:20){
                    Spacer()
                    Image("Bunt")
                        .resizable()
                        .scaledToFill()
                        .frame(width: 60, height: 85)
                    Spacer()
                    Image("Swing")
                        .resizable()
                        .scaledToFill()
                        .frame(width: 95, height: 60)
                    Spacer()
                    Image("Blast")
                        .resizable()
                        .scaledToFill()
                        .frame(width: 90, height: 80)
                    Spacer()
                }
            }
            VStack{
                HStack (spacing : 10){
                    
                        Button("Bunt Mode"){
                            showingPopover = true
                            }
                            .padding(13.0)
                            .background(Color(UIColor.lightGray))
                            .foregroundColor(.white)
                            .font(.headline)
                            .clipShape(Capsule())
                        
                    .popover(isPresented: $showingPopover){
                        BuntView()
                    }
                    
                            Button("Swing Mode"){
                                showingPopover1 = true
                            }
                            .padding(13.0)
                            .background(Color(UIColor.lightGray))
                            .foregroundColor(.white)
                            .font(.headline)
                            .clipShape(Capsule())
                    
                    .popover(isPresented: $showingPopover1){
                        SwingView()
                    }
                    
                    Button("Blast Mode"){
                        showingPopover2 = true
                    }
                            .padding(13.0)
                            .background(Color(UIColor.lightGray))
                            .foregroundColor(.white)
                            .font(.headline)
                            .clipShape(Capsule())
                    
                    .popover(isPresented: $showingPopover2){
                        FunView()
                    }
                    
                }
                Spacer()
               
            }
            
            .navigationTitle("Content View")
        
        
      }
        Spacer()
        Spacer()
      
    }
  .sheet(isPresented: $presented){ ScanView(bluetooth: bluetooth, presented: $presented, list: $list, isConnected: $isConnected) }
  .onAppear{ bluetooth.delegate = self }
}

func sendValue(_ value: Float) {
if Int(value) != Int(self.value) {
guard let sendValue = map(Int(value), of: 0...100, to: 0...255) else { return }
bluetooth.send([UInt8(state.int), UInt8(sendValue)])
}
self.value = value
}

func map(_ value: Int, of: ClosedRange, to: ClosedRange) -> Int? {
guard let ofmin = of.min(), let ofmax = of.max(), let tomin = to.min(), let tomax = to.max() else { return nil }
return Int(tomin + (tomax - tomin) * (value - ofmin) / (ofmax - ofmin))
}

}

struct BuntView: View{
@State private var angle0 = false
@State private var angle15 = false
@State private var angle45 = false
@State private var vibration = false
@State private var vibrationText = "OFF"
@State private var sound = false
@State private var soundText = "OFF"
@State private var light = false
@State private var lightText = "OFF"
@State private var negativeFeedback = false
@State private var negativeFeedbackText = "OFF"
@State private var blastMode = false
@State private var setAngle = -10
@State private var vibration1 = false
@State private var vibrationText1 = "OFF"
@State private var sound1 = false
@State private var soundText1 = "OFF"
@State private var light1 = false
@State private var lightText1 = "OFF"
@State private var negativeFeedback1 = false
@State private var negativeFeedbackText1 = "OFF"
@State private var blastMode1 = false
@State private var batSpeed = 0
@State private var currentView: Int = 0
@State private var Bunt = true
@State private var showingPopover = false
@State private var showingPopover1 = false
@State private var showingPopover2 = false
@State private var output:UInt16 = 0
@State private var batAngle:UInt16 = 0
@State private var batVelocity:UInt16 = 0

// Bluetooth Variables
var bluetooth = Bluetooth.shared
@State var presented: Bool = false
@State var list = [Bluetooth.Device]()
@State var isConnected: Bool = Bluetooth.shared.current != nil { didSet {
  if isConnected {
    presented.toggle()
  }
  else{
    angle45 = false
    angle0 = false
    angle15 = false
    light = false
    sound = false
    vibration = false
    blastMode = false
    negativeFeedback = false
    setAngle = -10
    vibrationText = "OFF"
    soundText = "OFF"
    lightText = "OFF"
    negativeFeedbackText = "OFF"
  }
} }

var body: some View {
if Bunt{
let degreeOfFreedom = 5
VStack{
Image("logo")
.resizable()
.scaledToFill()
.frame(width: 200, height: 70)
Image("Bunt")
.resizable()
.scaledToFill()
.frame(width: 60, height: 80)

        Text("Set Angle")
            .font(.title2)
            .bold()
            .italic()
        
        HStack {
            Spacer()
            Button {
                bluetooth.send(Array("1".utf8))
                self.angle0.toggle()
                self.angle15 = false
                self.angle45 = false
            } label: {
                ZStack {
                    Capsule()
                        .frame(width: 80, height: 40)
                        .foregroundColor(angle0 ? Color.green : Color.gray)
                    Text("0°")
                    
                        .bold()
                        .font(.title2)
                        .foregroundColor(.white)
                }
            }
            Spacer()
            Button {
                bluetooth.send(Array("2".utf8))
            } label: {
                ZStack {
                    Capsule()
                        .frame(width: 80, height: 40)
                        .foregroundColor(angle15 ? .green : .gray)
                    Text("15°")
                        .bold()
                        .font(.title)
                        .foregroundColor(.white)
                }
            }
            
            Spacer()
            Button {
                bluetooth.send(Array("3".utf8))
            } label: {
                ZStack {
                    Capsule()
                        .frame(width: 80, height: 40)
                        .foregroundColor(angle45 ? .green : .gray)
                    Text("45°")
                        .bold()
                        .font(.title)
                        .foregroundColor(.white)
                }
            }
            Spacer()
            
        }
        Text("Current Angle")
            .font(.title)
            .bold()
            .italic()
            .padding(.bottom, 5)
        
        Text(isConnected ? "\(batAngle)°" : "Not Connected")
            .bold()
            .font(.system(size: 52))
            .foregroundColor(isConnected ? (((batAngle < setAngle+degreeOfFreedom)&&(batAngle > setAngle-degreeOfFreedom)) ? .green : .black) : .red)
            .scaleEffect(isConnected ? 1.5 : 0.8)
            .offset(x: isConnected ? 10 : 0)
        VStack{
            Capsule()
                .frame(width: 350, height: 10)
                .foregroundColor(.gray)
            
            Text("Feedback")
                .font(.title)
                .bold()
                .italic()
            
            HStack{
                Text("Sound")
                    .font(.title)
                    .bold()
                    .italic()
                Spacer()
                Button {
                    if sound == true{
                        bluetooth.send(Array("b".utf8))
                    }
                    else{
                        bluetooth.send(Array("a".utf8))
                    }
                } label: {
                    ZStack {
                        Capsule()
                            .frame(width: 80, height: 40)
                            .foregroundColor(sound ? .green : .gray)
                            .animation(.linear)
                        Text("\(soundText)")
                            .bold()
                            .font(.title)
                            .foregroundColor(.white)
                    }
                }
            }
            .frame(width: 250, height: 50)
            
            HStack{
                Text("Light")
                    .font(.title)
                    .bold()
                    .italic()
                Spacer()
                Button {
                    //light.toggle()
                    if light == true{
                        bluetooth.send(Array("5".utf8))
                    }
                    else{
                        bluetooth.send(Array("4".utf8))
                    }
                } label: {
                    ZStack {
                        Capsule()
                            .frame(width: 80, height: 40)
                            .foregroundColor(light ? .green : .gray)
                            .animation(.linear)
                        Text("\(lightText)")
                            .bold()
                            .font(.title)
                            .foregroundColor(.white)
                    }
                }
            }
            .frame(width: 250, height: 50)
            
            HStack{
                Text("Vibration")
                    .font(.title)
                    .bold()
                    .italic()
                Spacer()
                Button {
                    if vibration == true{
                        bluetooth.send(Array("9".utf8))
                    }
                    else{
                        bluetooth.send(Array("8".utf8))
                    }
                } label: {
                    ZStack {
                        Capsule()
                            .frame(width: 80, height: 40)
                            .foregroundColor(vibration ? .green : .gray)
                            .animation(.linear)
                        
                        Text("\(vibrationText)")
                            .bold()
                            .font(.title)
                            .foregroundColor(.white)
                    }
                }
            }
            .frame(width: 250, height: 50)
            VStack{
                ZStack {
                    Capsule()
                        .frame(width: 300, height: 50)
                        .foregroundColor(.white)
                        .opacity(0.50)
                    
                    Text("Negative Feedback")
                        .font(.title)
                        .bold()
                        .italic()
                }
                Button {
                    if negativeFeedback == true{
                        if negativeFeedback == true{
                            bluetooth.send(Array("7".utf8))
                        }
                    }
                    else{
                        bluetooth.send(Array("6".utf8))
                    }
                } label: {
                    ZStack {
                        Capsule()
                            .frame(width: 80, height: 40)
                            .foregroundColor(negativeFeedback ? .green : .gray)
                            .animation(.linear)
                        Text("\(negativeFeedbackText)")
                            .bold()
                            .font(.title)
                            .foregroundColor(.white)
                    }
                }
            }
            .frame(width: 350, height: 90)
            .padding(.bottom)
            
        }
    }
}

}

}

struct SwingView: View {
@State private var Swing: Bool = true
var body: some View {
if Swing{
Text(/@START_MENU_TOKEN@/"Hello, World!"/@END_MENU_TOKEN@/)
}
}
}

struct FunView: View{
var body: some View{
NavigationView{
VStack{
Text("Blast Mode")
}
}

    }
   
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

struct BuntView_Previews: PreviewProvider {
static var previews: some View {
BuntView()
}
}

struct SwingView_Previews: PreviewProvider {
static var previews: some View {
SwingView()
}
}

struct FunView_Previews: PreviewProvider {
static var previews: some View {
FunView()
}
}

extension ContentView: BluetoothProtocol {
func state(state: Bluetooth.State) {
switch state {
case .unknown: print("◦ .unknown")
case .resetting: print("◦ .resetting")
case .unsupported: print("◦ .unsupported")
case .unauthorized: print("◦ bluetooth disabled, enable it in settings")
case .poweredOff: print("◦ turn on bluetooth")
case .poweredOn: print("◦ everything is ok")
case .error: print("• error")
case .connected:
print("◦ connected to (bluetooth.current?.name ?? "")")
isConnected = true
case .disconnected:
print("◦ disconnected")
isConnected = false
}
}

func list(list: [Bluetooth.Device]) { self.list = list }

func value(data: Data) { response = data }
}

Couple things:

  • bluetooth interaction (sending / receiving data over bluetooth) has nothing to do with UI. You can even do it in a separate non-UI target, debug it there and make it work. Once done - integrate it into the UI app.

  • make your Bluetooth class an "ObservableObject", move all state variables from views into Bluetooth class along with making them ""@Published" move all bt-related functionality into it (including what you currently do in didSets). In this case you'd not need delegate on bluetooth class. In the views reference bluetooth object as "@ObservedObject".

  • some people also split this further into a separate ViewModel class, sometimes per view, but typically that's needed only in a more complex project, in simple cases you can do without it.

  • Note that the delegate pattern should typically look like this:

protocol BluetoothDelegate: AnyObject {...}
...
weak var delegate: BluetoothDelegate?

if you follow this pattern you'd not have a chance mistakenly making a view a delegate (compiler would rightfully complain). Note that you can have a single delegate, and if you need "more than one delegate" you'd use some different mechanism (like combine, notificationCenter, your own code that manage an array of weakly captured delegate objects, etc). Try to get rid of your delegate initially, you may not even need it in this project.

  • quote the code properly! embed it into ``` (triple back tick brackets)

  • as a courtesy for the readers you should provide a minimal example. View aspects are not interesting on this forum (all those foreground / background colours and fonts and whatnot).

A sketch implementation:

class Bluetooth: ObservableObject {
    static let shared = Bluetooth()
    
    struct BluetoothState {
        var angle = 0
        // all vars here
    }
    
    @Published var state = BluetoothState()
    func turn() {/*...*/}
    ...
}

struct MyView: View {
    @ObservedObject private var bluetooth = Bluetooth.shared
    
    var body: some View {
        Button(String(bluetooth.state.angle)) {
            bluetooth.turn()
        }
    }
}