From 0cfeb287e63f51e325d15787c8683aee0cc367ec Mon Sep 17 00:00:00 2001 From: jess Date: Thu, 2 Apr 2026 18:30:31 -0700 Subject: [PATCH] add cl_factor UI and state to iOS cue --- cue-ios/CueIOS/AppState.swift | 6 ++++ cue-ios/CueIOS/Transport/UDPManager.swift | 1 + cue-ios/CueIOS/Views/CalibrateView.swift | 43 +++++++++++++++++++++++ cue-ios/CueIOS/Views/ChlorineView.swift | 6 ++++ 4 files changed, 56 insertions(+) diff --git a/cue-ios/CueIOS/AppState.swift b/cue-ios/CueIOS/AppState.swift index e3243e2..b623e4c 100644 --- a/cue-ios/CueIOS/AppState.swift +++ b/cue-ios/CueIOS/AppState.swift @@ -93,6 +93,8 @@ final class AppState { var calTempC: String = "40" var calCellConstant: Double? = nil var calRs: Double? = nil + var clFactor: Double? = nil + var clCalKnownPpm: String = "5" // Clean var cleanV: String = "1200" @@ -251,6 +253,10 @@ final class AppState { case .cellK(let k): calCellConstant = Double(k) status = String(format: "Device cell constant: %.4f cm\u{207B}\u{00B9}", k) + + case .clFactor(let f): + clFactor = Double(f) + status = String(format: "Device Cl factor: %.6f", f) } } diff --git a/cue-ios/CueIOS/Transport/UDPManager.swift b/cue-ios/CueIOS/Transport/UDPManager.swift index 6bafac0..726792f 100644 --- a/cue-ios/CueIOS/Transport/UDPManager.swift +++ b/cue-ios/CueIOS/Transport/UDPManager.swift @@ -95,6 +95,7 @@ final class UDPManager: @unchecked Sendable { send(buildSysexGetTemp()) send(buildSysexGetConfig()) send(buildSysexGetCellK()) + send(buildSysexGetClFactor()) startTimers() receiveLoop() diff --git a/cue-ios/CueIOS/Views/CalibrateView.swift b/cue-ios/CueIOS/Views/CalibrateView.swift index 95d41e7..23486a3 100644 --- a/cue-ios/CueIOS/Views/CalibrateView.swift +++ b/cue-ios/CueIOS/Views/CalibrateView.swift @@ -14,6 +14,7 @@ struct CalibrateView: View { inputSection resultsSection cellConstantSection + chlorineCalSection } .navigationTitle("Calibrate") } @@ -115,6 +116,48 @@ struct CalibrateView: View { } } + // MARK: - Chlorine calibration + + private var chlorineCalSection: some View { + Section("Chlorine Calibration") { + if let f = state.clFactor { + Text(String(format: "Cl factor: %.6f ppm/\u{00B5}A", f)) + } + if let r = state.clResult { + Text(String(format: "Last free Cl peak: %.3f \u{00B5}A", r.iFreeUa)) + } + + HStack { + Text("Known Cl ppm") + Spacer() + TextField("ppm", text: $state.clCalKnownPpm) + .multilineTextAlignment(.trailing) + .frame(width: 80) + #if os(iOS) + .keyboardType(.decimalPad) + #endif + } + + Button("Set Cl Factor") { + guard let r = state.clResult else { + state.status = "No chlorine measurement" + return + } + let knownPpm = Double(state.clCalKnownPpm) ?? 0 + let peak = abs(Double(r.iFreeUa)) + guard peak > 0 else { + state.status = "Peak current is zero" + return + } + let factor = knownPpm / peak + state.clFactor = factor + state.send(buildSysexSetClFactor(Float(factor))) + state.status = String(format: "Cl factor: %.6f ppm/\u{00B5}A", factor) + } + .disabled(state.clResult == nil) + } + } + // MARK: - Calculations private func saltGrams(volumeGal: Double, ppm: Double) -> Double { diff --git a/cue-ios/CueIOS/Views/ChlorineView.swift b/cue-ios/CueIOS/Views/ChlorineView.swift index 30f6951..9e2ba0b 100644 --- a/cue-ios/CueIOS/Views/ChlorineView.swift +++ b/cue-ios/CueIOS/Views/ChlorineView.swift @@ -68,6 +68,12 @@ struct ChlorineView: View { Text(String(format: "Combined: %.3f uA", r.iTotalUa - r.iFreeUa)) .foregroundStyle(.secondary) + if let f = state.clFactor { + let ppm = f * Double(abs(r.iFreeUa)) + Text(String(format: "Free Cl: %.2f ppm", ppm)) + .foregroundStyle(.cyan) + } + if let (_, refR) = state.clRef { Divider().frame(height: 16) Text(String(format: "vs Ref: dFree=%.3f dTotal=%.3f",