Hi All,
Please excuse my relatively basic question but I am new to swift programming and I am battling with a project.
I currently have an app that receives data from an Arduino using ble and displays the data as an integer. I used this medium article From Arduino programming to iOS App development as a guide for most of the functionality but changed the sensor data being sent to better suit my project requirements.
Based on the link above, I have all of the bluetooth handling in PeripheralUseCase.swift file and then I have the ConnectView file for the display:
@ObservedObject var viewModel: ConnectViewModel
@Environment(\.dismiss) var dismiss
@State var isToggleOn: Bool = false
@State var isPeripheralReady: Bool = false
@State var lastPressure: Int = 0
var body: some View {
VStack {
Text(viewModel.connectedPeripheral.name ?? "Unknown")
.font(.title)
ZStack {
CardView()
VStack {
Text("Surface")
HStack {
Button("Flats") {
viewModel.flats()
}
.disabled(!isPeripheralReady)
.buttonStyle(.borderedProminent)
Button("FlatPoint") {
viewModel.flatPoint()
}
.disabled(!isPeripheralReady)
.buttonStyle(.borderedProminent)
Button("Points") {
viewModel.points()
}
.disabled(!isPeripheralReady)
.buttonStyle(.borderedProminent)
}
}
}
ZStack {
CardView()
VStack {
Text("\(lastPressure) kPa")
.font(.largeTitle)
HStack {
Spacer()
.frame(alignment: .trailing)
Toggle("Notify", isOn: $isToggleOn)
.disabled(!isPeripheralReady)
Spacer()
.frame(alignment: .trailing)
}
}
}
Spacer()
.frame(maxHeight:.infinity)
Button {
dismiss()
} label: {
Text("Disconnect")
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
.padding(.horizontal)
}
.onChange(of: isToggleOn) { newValue in
if newValue == true {
viewModel.startNotifyPressure()
} else {
viewModel.stopNotifyPressure()
}
let startTime = Date().timeIntervalSince1970
}
.onReceive(viewModel.$state) { state in
switch state {
case .ready:
isPeripheralReady = true
case let .Pressure(temp):
lastPressure = temp
default:
print("Not handled")
}
}
}
}
struct PeripheralView_Previews: PreviewProvider {
final class FakeUseCase: PeripheralUseCaseProtocol {
var peripheral: Peripheral?
var onWriteLedState: ((Bool) -> Void)?
var onReadPressure: ((Int) -> Void)?
var onPeripheralReady: (() -> Void)?
var onError: ((Error) -> Void)?
func writeLedState(isOn: String) {}
func readPressure() {
onReadPressure?(25)
}
func notifyPressure(_ isOn: Bool) {}
}
static var viewModel = {
ConnectViewModel(useCase: FakeUseCase(),
connectedPeripheral: .init(name: "iOSArduinoBoard"))
}()
static var previews: some View {
ConnectView(viewModel: viewModel, isPeripheralReady: true)
}
}
struct CardView: View {
var body: some View {
RoundedRectangle(cornerRadius: 16, style: .continuous)
.shadow(color: Color(white: 0.5, opacity: 0.2), radius: 6)
.foregroundColor(.init(uiColor: .secondarySystemBackground))
}
}
With the associated View Model:
@Published var state = State.idle
var useCase: PeripheralUseCaseProtocol
let connectedPeripheral: Peripheral
init(useCase: PeripheralUseCaseProtocol,
connectedPeripheral: Peripheral) {
self.useCase = useCase
self.useCase.peripheral = connectedPeripheral
self.connectedPeripheral = connectedPeripheral
self.setCallbacks()
}
private func setCallbacks() {
useCase.onPeripheralReady = { [weak self] in
self?.state = .ready
}
useCase.onReadPressure = { [weak self] value in
self?.state = .Pressure(value)
}
useCase.onWriteLedState = { [weak self] value in
self?.state = .ledState(value)
}
useCase.onError = { error in
print("Error \(error)")
}
}
func startNotifyPressure() {
useCase.notifyPressure(true)
}
func stopNotifyPressure() {
useCase.notifyPressure(false)
}
func readPressure() {
useCase.readPressure()
}
func flats() {
useCase.writeLedState(isOn: "1")
}
func flatPoint() {
useCase.writeLedState(isOn: "2")
}
func points() {
useCase.writeLedState(isOn: "3")
}
}
extension ConnectViewModel {
enum State {
case idle
case ready
case Pressure(Int)
case ledState(Bool)
}
}
What I am now trying to do is plot the data that is received from the Arduino in a line graph as it is received. Preferably the graph will scroll with time as well.