Skip to content

Commit

Permalink
Merge pull request JohanDegraeve#580 from paulplant/stelo
Browse files Browse the repository at this point in the history
Dexcom Stelo implementation
  • Loading branch information
JohanDegraeve authored Oct 19, 2024
2 parents b176bc9 + 05f27a1 commit 598b260
Show file tree
Hide file tree
Showing 15 changed files with 41 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ enum BluetoothPeripheralType: String, CaseIterable {
case DexcomType = "Dexcom G5 / G6 / ONE"

/// Dexcom G7
case DexcomG7Type = "Dexcom G7 / ONE+"
case DexcomG7Type = "Dexcom G7 / ONE+ / Stelo"

/// DexcomG4
case DexcomG4Type = "Dexcom G4 (Bridge)"
Expand All @@ -53,8 +53,7 @@ enum BluetoothPeripheralType: String, CaseIterable {
case Libre3HeartBeatType = "Libre/Generic HeartBeat"

/// DexcomG7 heartbeat
case DexcomG7HeartBeatType = "Dexcom G7/ONE+ HeartBeat"

case DexcomG7HeartBeatType = "Dexcom G7/ONE+/Stelo HeartBeat"

/// omnipod heartbeat
case OmniPodHeartBeatType = "OmniPod HeartBeat"
Expand Down
26 changes: 17 additions & 9 deletions xdrip/BluetoothTransmitter/CGM/Dexcom/G7/CGMG7Transmitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import os

class CGMG7Transmitter: BluetoothTransmitter, CGMTransmitter {

/// is the transmitter oop web enabled or not. For G7/ONE+ this must be set to true to use only the transmitter algorithm
/// is the transmitter oop web enabled or not. For G7/ONE+/Stelo this must be set to true to use only the transmitter algorithm
private var webOOPEnabled: Bool

/// stored when receiving single reading, needed when receiving backfill data
Expand Down Expand Up @@ -112,7 +112,7 @@ class CGMG7Transmitter: BluetoothTransmitter, CGMTransmitter {
init(address:String?, name: String?, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMG7TransmitterDelegate: CGMG7TransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate) {

// assign addressname and name or expected devicename
// For G7/ONE+ we don't listen for a specific device name. Dexcom uses an advertising id, which already filters out all other devices (like tv's etc. We will verify in another way that we have the current active G7/ONE+, and not an old one, which is still near
// For G7/ONE+/Stelo we don't listen for a specific device name. Dexcom uses an advertising id, which already filters out all other devices (like tv's etc. We will verify in another way that we have the current active G7/ONE+/Stelo, and not an old one, which is still near
var newAddressAndName: BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "DX")

if let name = name {
Expand Down Expand Up @@ -210,10 +210,16 @@ class CGMG7Transmitter: BluetoothTransmitter, CGMTransmitter {
return
}

let maxSensorAgeInDays = ConstantsDexcomG7.maxSensorAgeInDays
var maxSensorAgeInDays = ConstantsDexcomG7.maxSensorAgeInDays

// check if it's a Stelo and if so, update the maxSensorAge
if let transmitterIdString = UserDefaults.standard.activeSensorTransmitterId, transmitterIdString.startsWith("DX01") {
maxSensorAgeInDays = ConstantsDexcomG7.maxSensorAgeInDaysStelo
}

let sensorAgeInDays = Double(round((g7GlucoseMessage.sensorAge / 3600 / 24) * 10) / 10)

// G7/ONE+ has the peculiarity that it will keep sending/repeating the same BG value (without ever changing) via BLE even after the session officially ends.
// G7/ONE+/Stelo has the peculiarity that it will keep sending/repeating the same BG value (without ever changing) via BLE even after the session officially ends.
// to avoid this, let's check if the sensor is still within maxSensorAge before we continue
guard sensorAgeInDays < maxSensorAgeInDays else {
trace(" G7 is expired so will not process reading. sensorAge: %{public}@ / maxSensorAgeInDays: %{public}@", log: log, category: ConstantsLog.categoryCGMG7, type: .error, sensorAgeInDays.description, maxSensorAgeInDays.description)
Expand Down Expand Up @@ -285,7 +291,7 @@ class CGMG7Transmitter: BluetoothTransmitter, CGMTransmitter {

} else {

trace("Connected to Dexcom G7 that is not paired and/or authenticated by other app. Will disconnect and scan for another Dexcom G7", log: log, category: ConstantsLog.categoryCGMG7, type: .info )
trace("Connected to Dexcom G7 that is not paired and/or authenticated by other app. Will disconnect and scan for another Dexcom G7/ONE+/Stelo", log: log, category: ConstantsLog.categoryCGMG7, type: .info )

disconnectAndForget()

Expand Down Expand Up @@ -370,9 +376,11 @@ class CGMG7Transmitter: BluetoothTransmitter, CGMTransmitter {


func maxSensorAgeInDays() -> Double? {

return ConstantsDexcomG7.maxSensorAgeInDays

if let transmitterIdString = UserDefaults.standard.activeSensorTransmitterId, transmitterIdString.startsWith("DX01") {
return ConstantsDexcomG7.maxSensorAgeInDaysStelo
} else {
return ConstantsDexcomG7.maxSensorAgeInDays
}
}

func getCBUUID_Service() -> String {
Expand All @@ -392,7 +400,7 @@ class CGMG7Transmitter: BluetoothTransmitter, CGMTransmitter {
// MARK: - private functions
@objc private func authenticationFailed() {

trace("Connected to Dexcom G7 but authentication not received. Will disconnect and scan for another Dexcom G7", log: log, category: ConstantsLog.categoryCGMG7, type: .info )
trace("Connected to Dexcom G7 but authentication not received. Will disconnect and scan for another Dexcom G7/ONE+/Stelo", log: log, category: ConstantsLog.categoryCGMG7, type: .info )

disconnectAndForget()

Expand Down
6 changes: 4 additions & 2 deletions xdrip/BluetoothTransmitter/CGM/Generic/CGMTransmitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ enum CGMTransmitterType:String, CaseIterable {
case dexcom = "Dexcom G5/G6/ONE"

/// dexcom G7
case dexcomG7 = "Dexcom G7/ONE+"
case dexcomG7 = "Dexcom G7/ONE+/Stelo"

/// miaomiao
case miaomiao = "MiaoMiao"
Expand Down Expand Up @@ -312,7 +312,9 @@ enum CGMTransmitterType:String, CaseIterable {

case .dexcomG7:
if let transmitterIdString = UserDefaults.standard.activeSensorTransmitterId {
if transmitterIdString.startsWith("DX02") {
if transmitterIdString.startsWith("DX01") {
return "Dexcom Stelo"
} else if transmitterIdString.startsWith("DX02") {
return "Dexcom ONE+"
}
}
Expand Down
3 changes: 3 additions & 0 deletions xdrip/Constants/ConstantsDexcomG7.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ enum ConstantsDexcomG7 {
/// how many days the sensor session lasts. In the case of G7/ONE+ it is 10 days + a 12 hour grace period = 10.5 days
static let maxSensorAgeInDays: Double = 10.5

/// how many days the sensor session lasts. In the case of Stelo it is 15 days + a 12 hour grace period = 15.5 days
static let maxSensorAgeInDaysStelo: Double = 15.5

}
2 changes: 1 addition & 1 deletion xdrip/Extensions/ChartPoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ extension ChartPoint {

}

extension ChartPoint: Comparable {
extension SwiftCharts.ChartPoint: Swift.Comparable {

public static func < (lhs: ChartPoint, rhs: ChartPoint) -> Bool {

Expand Down
2 changes: 1 addition & 1 deletion xdrip/Extensions/Double.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

extension Double: RawRepresentable {
extension Swift.Double: Swift.RawRepresentable {

//MARK: - copied from https://github.com/LoopKit/LoopKit

Expand Down
2 changes: 1 addition & 1 deletion xdrip/Managers/Watch/WatchManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ final class WatchManager: NSObject, ObservableObject {
var deltaValueInUserUnit: Double = 0.0

// add delta if available
if bgReadings.count > 0 {
if bgReadings.count > 1 {

previousValueInUserUnit = bgReadings[1].calculatedValue.mgDlToMmol(mgDl: isMgDl)
actualValueInUserUnit = bgReadings[0].calculatedValue.mgDlToMmol(mgDl: isMgDl)
Expand Down
1 change: 1 addition & 0 deletions xdrip/Storyboards/de.lproj/BluetoothPeripheralView.strings
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,4 @@
"confirmAlgorithmChangeToxDripMessage" = "itte um Bestätigung, dass zum xDrip Algorithmus gewechselt werden soll.\n\nDies stoppt für kurze Zeit die Datenübermittlung und Du wirst um einen initialen Kalibrierungswert (Blut) gebeten.";
"confirmCalibrationChangeToSinglePointMessage" = "Bitte um Bestätigung, dass zur Standard Kalibrierung gewechselt werden soll.\n\nDies stoppt für kurze Zeit die Datenübermittlung und Du wirst um einen initialen Kalibrierungswert (Blut) gebeten.";
"confirmCalibrationChangeToMultiPointMessage" = "Bitte um Bestätigung, dass zur Mehrpunkt Kalibrierung gewechselt werden soll.\n\n⚠️ Diese Methode ist nur für erfahrene Benutzer, es könnte ein falscher und damit gefährlicher Wert angezeigt werden, wenn die Kalibrierung nicht korrekt durchgeführt wurde.\n\nWenn Du unsicher bist, bitte drücke Abbruch/Cancel.";
"confirm" = "Bestätigen";
2 changes: 2 additions & 0 deletions xdrip/Storyboards/de.lproj/Common.strings
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,5 @@

/// the words in user range
"common_statistics_userRange" = "User Range";

"common_notRequired" = "Nicht Erforderlich";
2 changes: 1 addition & 1 deletion xdrip/Storyboards/de.lproj/SettingsViews.strings
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@
"settingsviews_webooptransmitter" = "Use Transmitter Algorithm";

/// weboop settings, title of the dialogs where user can select between xdrip or transmitter algorithm
"settingsviews_labelWebOOP" = "xDrip or Transmitter Algorithm";
"settingsviews_labelWebOOP" = "xdrip oder nativer Algorithmus";

"settingsviews_showHelpIcon" = "Hilfe-Symbol anzeigen";
"settingsviews_restartNeeded" = "(Neustart notwendig)";
Expand Down
4 changes: 4 additions & 0 deletions xdrip/Storyboards/fr.lproj/BluetoothPeripheralView.strings
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,7 @@

"nativeAlgorithm" = "Algorithme natif";
"xDripAlgorithm" = "Algorithme xDrip";
"confirmAlgorithmChangeToTransmitterMessage" = "Confirmer le changement pour revenir à l'algorithme natif/transmetteur";
"confirmAlgorithmChangeToxDripMessage" = "Confirmer le changement pour utiliser l'algorithme xDrip.\n\nLes lectures vont s'interrompre un moment et vous devrez insérer une valeur de calibration initiale.";
"confirmCalibrationChangeToSinglePointMessage" = "Confirmer le changement du type de calibration à standard\n\nLes lectures vont s'interrompre un moment et vous devrez insérer une valeur de calibration initiale.";
"confirmCalibrationChangeToMultiPointMessage" = "Confirmer le changement du type de calibration à multipoints\n\n⚠️ Notez que cette méthode est réservée aux utilisateurs expérimentés car elle peut générer des résultats dangereux en cas de calibration incorrecte.\n\nSi vous n'êtes pas sûr de savoir l'utiliser, sélectionnez Annuler.";
2 changes: 1 addition & 1 deletion xdrip/Storyboards/fr.lproj/HomeView.strings
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"notknown" = "Inconnu";
"lastconnection" = "Dernière Connexion";
"transmitterbatterylevel" = "Niveau de batterie (Transmitteur)";
"ago" = "passée(s)";
"ago" = "avant";
"licenseinfo" = "This program is free software distributed under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.\r\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.\r\n\nSee http://www.gnu.org/licenses/gpl.txt for more details.\r\n\r\nInfo: ";
"info" = "Informations";
"transmitterinfo" = "Tout d'abord, allez sur l'écran Bluetooth où vous pourrez ajouter et scanner votre transmetteur.\r\n\nPuis revenir sur l'écran d'accueil pour démarrer le capteur.";
Expand Down
1 change: 1 addition & 0 deletions xdrip/Storyboards/sv.lproj/BluetoothPeripheralView.strings
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@
"confirmAlgorithmChangeToxDripMessage" = "Bekräfta att du vill ändra till xDrip-algoritmen.\n\nDetta stoppar avläsningarna under en kort tid och du kommer få ange ett initialt kalibreringsvärde.";
"confirmCalibrationChangeToSinglePointMessage" = "Bekräfta att du vill ändra kalibreringstypen till Standardkalibrering\n\nDetta stoppar avläsningarna under en kort tid och du kommer få ange ett initialt kalibreringsvärde.";
"confirmCalibrationChangeToMultiPointMessage" = "Bekräfta att du vill ändra kalibreringstypen till Flerpunktskalibrering\n\n⚠️ Observera att denna metod endast är för avancerade användare och kan potentiellt ge farliga resultat om kalibreringen inte är korrekt utförd.\n\n Om du är osäker på hur man använder denna metod, vänligen tryck på avbryt.";
"confirm" = "Bekräfta";
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ extension DexcomG7BluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
}

func sectionTitle(forSection section: Int) -> String {
return "Dexcom G7 / ONE+"
return "Dexcom G7 / ONE+ / Stelo"
}

func update(cell: UITableViewCell, forRow rawValue: Int, forSection section: Int, for bluetoothPeripheral: BluetoothPeripheral) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ extension DexcomG7HeartBeatBluetoothPeripheralViewModel: BluetoothPeripheralView
func sectionTitle(forSection section: Int) -> String {

// there's no section specific for this type of transmitter, this function will not be called
return "Dexcom G7/ONE+ Heartbeat ♥"
return "Dexcom G7/ONE+/Stelo Heartbeat ♥"

}

Expand Down

0 comments on commit 598b260

Please sign in to comment.