Hello Everyone,
Thanks so much for taking a look at my code. I am just a newbie, and have been in the process of making my first app. Most of this is cobbled together from bits and pieces of other code that I found, and then modified. Weirdest problem. The Bluetooth runs fine and I can see the data on my App no issues. But the timer does not run. (does display). As soon as I stop Bluetooth from running, (I have an Arduino nano), the timer begins running again. There are no errors shown in Xcode so I am sort stuck on where to look.
Below is full Bluetooth Code:
import Foundation
import CoreBluetooth
enum ConnectionStatus: String {
case connected
case disconnected
case scanning
case connecting
case error
}
let BarrelBaristaService: CBUUID = CBUUID(string: "4FAFC201-1FB5-459E-8FCC-C5C9C331914B")
//Temperature F
let TemperatureCharacteristic: CBUUID = CBUUID(string: "5D54D470-8B08-4368-9E8F-03191A0314A5")
//Humidity %
let HumidityCharacteristic: CBUUID = CBUUID(string: "B2F5E988-C50F-4200-A1D9-5884F9417DEF")
//Weight %
let WeightCharacteristic: CBUUID = CBUUID(string: "BEB5483E-36E1-4688-B7F5-EA07361B26A8")
class BluetoothService: NSObject, ObservableObject {
private var centralManager: CBCentralManager!
var BarrelBarristaPeripheral: CBPeripheral?
@Published var peripheralStatus: ConnectionStatus = .disconnected
@Published var TempValue: Float = 0
@Published var HumidValue: Float = 0
@Published var WeightValue: Float = 0
@Published var Connected: Bool = false
override init() {
super.init()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func scanForPeripherals() {
peripheralStatus = .scanning
centralManager.scanForPeripherals(withServices: nil)
}
}
extension BluetoothService: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("CB Powered On")
scanForPeripherals()
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if peripheral.name == "Barrel Barista" {
print("Discovered \(peripheral.name ?? "no name")")
BarrelBarristaPeripheral = peripheral
centralManager.connect(BarrelBarristaPeripheral!)
peripheralStatus = .connecting
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheralStatus = .connected
Connected = true
peripheral.delegate = self
peripheral.discoverServices([BarrelBaristaService])
centralManager.stopScan()
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
peripheralStatus = .disconnected
Connected = false
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
peripheralStatus = .error
print(error?.localizedDescription ?? "no error")
}
}
extension BluetoothService: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services ?? [] {
if service.uuid == BarrelBaristaService {
print("found service for \(BarrelBaristaService)")
peripheral.discoverCharacteristics([TemperatureCharacteristic], for: service)
peripheral.discoverCharacteristics([HumidityCharacteristic], for: service)
peripheral.discoverCharacteristics([WeightCharacteristic], for: service)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for characteristic in service.characteristics ?? [] {
peripheral.setNotifyValue(true, for: characteristic)
print("found characteristic, waiting on values.")
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic.uuid == TemperatureCharacteristic {
guard let data = characteristic.value else {
print("No data received for \(characteristic.uuid.uuidString)")
return
}
let TempData: Float = data.withUnsafeBytes { $0.pointee }
TempValue = TempData
}
if characteristic.uuid == HumidityCharacteristic {
guard let data = characteristic.value else {
print("No data received for \(characteristic.uuid.uuidString)")
return
}
let HumidData: Float = data.withUnsafeBytes { $0.pointee }
HumidValue = HumidData
}
if characteristic.uuid == WeightCharacteristic {
guard let data = characteristic.value else {
print("No data received for \(characteristic.uuid.uuidString)")
return
}
let WeightData: Float = data.withUnsafeBytes { $0.pointee }
WeightValue = WeightData
}
}
}
Below is Starting App code:
import SwiftUI
@main
struct Barrel_BaristaApp: App {
@ObservedObject var bluetoothService = BluetoothService()
var body: some Scene {
WindowGroup {
SplashScreenView()
.environmentObject(bluetoothService)
}
}
}
Below is where the timer appears in the View:
import SwiftUI
import UIKit
import Foundation
struct ContentView: View {
@EnvironmentObject var bluetoothService: BluetoothService
@Binding var whiskyname: String
@Binding var barrelabv: String
@Binding var imageSelected: UIImage
@Binding var weightlownum: Float32
@Binding var weighthinum: Float32
@Binding var screenDisable: Bool
@State var pourabv: String = ""
@State var TempValue: String = ""
@State var link = UIImage()
@State var timeinterval = Date()
@State var percentFilled: Float = 0
@State var timeFormat: String = "Days"
@State var timeremaining: String = ""
let formatPicker: [String] = ["Seconds","Minutes","Hours","Days", "Weeks", "Months"]
let calendar = Calendar.current
let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
let futuredate: Date = Calendar.current.date(byAdding: .second, value:0, to: Date()) ?? Date ()
func updateTimeRemaining() {
let remaining = Calendar.current.dateComponents([.year, .month, .weekOfYear, .hour, .minute, .second], from: futuredate, to: Date())
let year = remaining.year ?? 0
let month = remaining.month ?? 0
let week = remaining.weekOfYear ?? 0
let day = remaining.day ?? 0
let hour = remaining.hour ?? 0
let minute = remaining.minute ?? 0
let second = remaining.second ?? 0
timeremaining = "Whisky has been aging for \(year) Years \(month) Months \(week) Weeks \(day) Days \(hour) Hours \(minute) Minutes \(second) Seconds"
}
var body: some View {
NavigationStack{
NavigationLink {
SetupView()
} label: {
}
.onReceive(timer, perform: { _ in
updateTimeRemaining()
})
VStack{
Text(self.whiskyname)
.frame(width: 300, height:1)
.font(.system(size: 24))
}
VStack{
Image(uiImage: imageSelected)
.resizable()
.font(.system(size: 40))
.aspectRatio(contentMode: .fill)
.frame(width:245, height:245)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
.padding(.vertical, 10)
}
VStack(alignment: .leading){
HStack{
if bluetoothService.Connected == true{
let link = Image(systemName: "link.circle.fill").foregroundColor(.blue)
link
Text("Bluetooth Connected")
.font(.footnote)
} else {
let link = Image(systemName: "link.circle.fill").foregroundColor(.red)
link
Text("Bluetooth Disconnected")
.font(.footnote)
}
}
HStack{
TextField("", text: $pourabv)
.padding(20)
.font(.system(size: 30))
.frame(width: 80, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text(" % Pour ABV")
.font(.system(size: 30))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
Text("\(bluetoothService.TempValue, specifier: "%.1f")°")
.font(.system(size: 30))
.frame(width: 110, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Temperature F")
.font(.system(size: 30))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
Text("\(bluetoothService.HumidValue, specifier: "%.1f") %")
.font(.system(size: 30))
.frame(width: 110, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Humidity")
.font(.system(size: 30))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
let percent = (100 / (weighthinum - weightlownum)) * (bluetoothService.WeightValue - weightlownum)
Text("\(percent, specifier: "%.1f") %")
.font(.system(size: 30))
.frame(width: 110, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Barrel Filled")
.font(.system(size: 30))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
let myString = (barrelabv)
let floatbarrelabv = (myString as NSString).floatValue
let myString2 = (pourabv)
let floatpourabv = (myString2 as NSString).floatValue
let glasses = (((((1.8 * floatbarrelabv * (100 / (weighthinum - weightlownum)) * (bluetoothService.WeightValue - weightlownum))) / floatpourabv) * 3785.41) / 40) / 100
Image("whisky glass")
.resizable()
.frame(width: 50, height:50)
Text("\(glasses, specifier: "%.0f")")
.font(.system(size: 30))
.padding(20)
.frame(width: 105, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Glasses remaining")
.font(.system(size: 25))
.frame(width: 200, height:35)
.font(.system(size: 24))
.cornerRadius(15)
}
HStack{
let myString = (barrelabv)
let floatbarrelabv = (myString as NSString).floatValue
let myString2 = (pourabv)
let floatpourabv = (myString2 as NSString).floatValue
let bottles = (((((1.8 * floatbarrelabv * (100 / (weighthinum - weightlownum)) * (bluetoothService.WeightValue - weightlownum))) / floatpourabv) * 3785.41) / 750) / 100
Image("bottle")
.resizable()
.frame(width: 50, height:50)
Text("\(bottles, specifier: "%.1f")")
.font(.system(size: 30))
.padding(20)
.frame(width: 105, height:35)
.font(.system(size: 24))
.background(Color.blue.opacity(0.4))
.cornerRadius(15)
Text("Bottles remaining")
.font(.system(size: 25))
.frame(width: 200, height:40)
.font(.system(size: 24))
.cornerRadius(15)
}
Text(timeremaining)
} //Main VStack ends here
Spacer()
} //Navigation Stack
} // body view
} // Content View
struct ContentView_Previews: PreviewProvider {
@State static var whiskyname: String = ""
@State static var barrelabv: String = ""
@State static var weighthinum: Float32 = 0
@State static var weightlownum: Float32 = 0
@State static var imageSelected = UIImage()
@State static var screenDisable: Bool = false
@State var link = UIImage()
@State static var bottles: Float32 = 0
static var previews: some View{
ContentView(whiskyname: $whiskyname, barrelabv: $barrelabv, imageSelected: $imageSelected, weightlownum: $weightlownum, weighthinum: $weighthinum, screenDisable: $screenDisable)
.environmentObject(BluetoothService())
}
}
Thanks so much for taking a look at this. I am just starting out, and this is stopping me from progressing. There are no errors shown in Xcode, just does not work properly. Thanks again...
Dan