Contenidos
Aplicación en Apple Watch
Permisos
Código de la aplicación para Apple Watch que envía la medición de oxígeno en sangre cuando se pulsa a un botón
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
import SwiftUI import HealthKit class SpO2Manager: NSObject, ObservableObject { private let healthStore = HKHealthStore() @Published var SpO2Text = "Niveles de oxígeno: No disponible" var query: HKObserverQuery? override init() { super.init() } func startSpO2Readings() { guard let SpO2Type = HKObjectType.quantityType(forIdentifier: .oxygenSaturation) else { SpO2Text = "La medición de oxígeno en sangre no está disponible en este dispositivo." return } healthStore.requestAuthorization(toShare: nil, read: [SpO2Type]) { [weak self] (success, error) in if success { self?.createSpO2StreamingQuery() } else { self?.SpO2Text = "No se pudo obtener permiso para acceder a la medición de oxígeno." } } } private func createSpO2StreamingQuery() { guard let SpO2Type = HKObjectType.quantityType(forIdentifier: .oxygenSaturation) else { return } query = HKObserverQuery(sampleType: SpO2Type, predicate: nil) { [weak self] query, completionHandler, error in guard let self = self else { return } let anchoredQuery = HKAnchoredObjectQuery(type: SpO2Type, predicate: nil, anchor: nil, limit: HKObjectQueryNoLimit) { query, samples, deletedObjects, anchor, error in guard let samples = samples as? [HKQuantitySample], let sample = samples.last else { return } let value = sample.quantity.doubleValue(for: HKUnit.percent()) DispatchQueue.main.async { [weak self] in self?.SpO2Text = "Nivel: \(value)" } // Envío de datos al servidor self.sendSpO2ToServer() } self.healthStore.execute(anchoredQuery) completionHandler() } healthStore.execute(query!) healthStore.enableBackgroundDelivery(for: SpO2Type, frequency: .immediate) { success, error in if success { print("Background delivery enabled for SpO2 readings") } else { if let error = error { print("Error enabling background delivery: \(error.localizedDescription)") } else { print("Error enabling background delivery") } } } } func sendSpO2ToServer() { guard let value = Float(SpO2Text.components(separatedBy: " ").last ?? "") else { print("No se puede convertir el valor de SpO2 a Float") return } let messageToSend = "Niveles de oxígeno: \(value)" if let url = URL(string: "http://192.168.1.55:6002/send-spo2") { var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/text", forHTTPHeaderField: "Content-Type") let data = messageToSend.data(using: .utf8) request.httpBody = data let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { print("Error: \(error.localizedDescription)") } else if let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) { print("Niveles de oxígeno enviados con éxito") } else { print("Error al enviar los niveles de oxígeno") } } task.resume() } else { print("URL no válida") } } } struct ContentView: View { @ObservedObject var SpO2Manager: SpO2Manager init(SpO2Manager: SpO2Manager) { self.SpO2Manager = SpO2Manager } var body: some View { VStack { Text(SpO2Manager.SpO2Text) .padding() Button("Iniciar medición de oxígeno en sangre") { SpO2Manager.startSpO2Readings() } .padding() Button("Enviar al servidor") { SpO2Manager.sendSpO2ToServer() } .padding() } } } @main struct SpO2App: App { let spo2Manager = SpO2Manager() var body: some Scene { WindowGroup { ContentView(SpO2Manager: spo2Manager) } } } |
Servidor web que recibe la medición y almacena en un fichero
Importar librerías
1 2 3 4 |
io.ktor:ktor-server-netty:1.6.7 io.ktor:ktor-gson:1.6.7 org.slf4j:slf4j-simple:2.0.0-alpha1 org.slf4j:slf4j-simple:1.7.32 |
Código del servidor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import io.ktor.application.* import io.ktor.http.* import io.ktor.request.* import io.ktor.response.* import io.ktor.routing.* import io.ktor.server.engine.* import io.ktor.server.netty.* import java.io.File fun main() { val server = embeddedServer(Netty, port = 6002) { routing { post("/send-spo2") { val receivedMessage = call.receiveText() println("Mensaje recibido: $receivedMessage") // Escribe los valores en un archivo writeToFile(receivedMessage) call.respond(HttpStatusCode.OK, "Mensaje recibido: $receivedMessage") } } } server.start(wait = true) } // Función para escribir en un archivo fun writeToFile(message: String) { val file = File("valores.txt") // Nombre del archivo donde se almacenarán los valores file.appendText("$message\n") // Agrega el nuevo valor al archivo (con un salto de línea) } |