bluereader, not tested, battery level not supported
This commit is contained in:
parent
9b6b638ad6
commit
81128ff7ee
|
@ -61,6 +61,7 @@
|
|||
F85DC2F421CFE3D400B9F74A /* Sensor+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DC2F121CFE3D400B9F74A /* Sensor+CoreDataClass.swift */; };
|
||||
F85DC2F521CFE3D400B9F74A /* BgReading+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DC2F221CFE3D400B9F74A /* BgReading+CoreDataClass.swift */; };
|
||||
F867E2612252ADAB000FD265 /* Calibration+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F867E25D2252ADAB000FD265 /* Calibration+CoreDataProperties.swift */; };
|
||||
F889CB60236C3DCB00A81068 /* CGMBlueReaderTransmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F889CB5F236C3DCB00A81068 /* CGMBlueReaderTransmitter.swift */; };
|
||||
F897AAF92200F2D200CDDD10 /* CBPeripheralState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F897AAF82200F2D200CDDD10 /* CBPeripheralState.swift */; };
|
||||
F897AAFB2201018800CDDD10 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = F897AAFA2201018800CDDD10 /* String.swift */; };
|
||||
F898EDEA233F53BF00BFB79B /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898EDE9233F53BF00BFB79B /* UIButton.swift */; };
|
||||
|
@ -305,6 +306,7 @@
|
|||
F85DC2F121CFE3D400B9F74A /* Sensor+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Sensor+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||
F85DC2F221CFE3D400B9F74A /* BgReading+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BgReading+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||
F867E25D2252ADAB000FD265 /* Calibration+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Calibration+CoreDataProperties.swift"; path = "xdrip/Core Data/extensions/Calibration+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
|
||||
F889CB5F236C3DCB00A81068 /* CGMBlueReaderTransmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGMBlueReaderTransmitter.swift; sourceTree = "<group>"; };
|
||||
F897AAF82200F2D200CDDD10 /* CBPeripheralState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBPeripheralState.swift; sourceTree = "<group>"; };
|
||||
F897AAFA2201018800CDDD10 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
|
||||
F898EDE9233F53BF00BFB79B /* UIButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIButton.swift; sourceTree = "<group>"; };
|
||||
|
@ -911,6 +913,14 @@
|
|||
path = GenericBluetoothTransmitter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F889CB5E236C3DA600A81068 /* BlueReader */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F889CB5F236C3DCB00A81068 /* CGMBlueReaderTransmitter.swift */,
|
||||
);
|
||||
path = BlueReader;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F8A389B82315DB080010F405 /* M5Stack */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1036,6 +1046,7 @@
|
|||
F8A54AEC22D9156600934E7A /* Libre */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F889CB5E236C3DA600A81068 /* BlueReader */,
|
||||
F8C5EBE822F49AB300563B5F /* Droplet */,
|
||||
EE9947E622EEDD0700DCB876 /* Bubble */,
|
||||
F8A54AFB22D9179100934E7A /* Utilities */,
|
||||
|
@ -1716,6 +1727,7 @@
|
|||
F8EEDD6423020FAD00D2D610 /* NoCalibrator.swift in Sources */,
|
||||
F8EEDD5422FF685400D2D610 /* NSMutableURLRequest.swift in Sources */,
|
||||
F897AAFB2201018800CDDD10 /* String.swift in Sources */,
|
||||
F889CB60236C3DCB00A81068 /* CGMBlueReaderTransmitter.swift in Sources */,
|
||||
F8A389CA232118E80010F405 /* M5StackBluetoothDelegate.swift in Sources */,
|
||||
F8B3A847227F090E004BA588 /* SettingsViewNightScoutSettingsViewModel.swift in Sources */,
|
||||
F8B3A79622635A25004BA588 /* AlertEntry+CoreDataClass.swift in Sources */,
|
||||
|
|
|
@ -8,6 +8,7 @@ enum ConstantsDefaultAlertLevels {
|
|||
static let defaultBatteryAlertLevelGNSEntry = 20
|
||||
static let defaultBatteryAlertLevelBlucon = 20
|
||||
static let defaultBatteryAlertLevelDroplet = 20
|
||||
static let defaultBatteryAlertLevelBlueReader = 20
|
||||
|
||||
// blood glucose level alert values in mgdl
|
||||
static let veryHigh = 250
|
||||
|
|
|
@ -82,6 +82,9 @@ enum ConstantsLog {
|
|||
/// droplet 1
|
||||
static let categoryCGMDroplet1 = "categoryCGMDroplet1"
|
||||
|
||||
/// bluereader
|
||||
static let categoryCGMBlueReader = "categoryCGMBlueReader"
|
||||
|
||||
/// LibreOOPClient
|
||||
static let categoryLibreOOPClient = "categoryLibreOOPClient"
|
||||
|
||||
|
|
|
@ -82,6 +82,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
/// Droplet
|
||||
case Droplet1 = "Droplet-1"
|
||||
|
||||
/// BlueReader
|
||||
case blueReader = "BlueReader"
|
||||
|
||||
/// does the transmitter need a transmitter id ?
|
||||
///
|
||||
/// can be used in UI stuff, if reset not possible then there's no need to show that option in the settings UI
|
||||
|
@ -106,6 +109,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .Droplet1:
|
||||
return false
|
||||
|
||||
case .blueReader:
|
||||
return false
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +142,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .Droplet1:
|
||||
return false
|
||||
|
||||
case .blueReader:
|
||||
return false
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,6 +175,8 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .Droplet1:
|
||||
return false
|
||||
|
||||
case .blueReader:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,6 +213,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
// todo: validate transmitter id for blucon
|
||||
return nil
|
||||
|
||||
case .blueReader:
|
||||
return nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,6 +244,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .Droplet1:
|
||||
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelDroplet
|
||||
|
||||
case .blueReader:
|
||||
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelBlueReader
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,6 +275,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .Droplet1:
|
||||
return false
|
||||
|
||||
case .blueReader:
|
||||
return false
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,6 +302,10 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
|
||||
case .Blucon:
|
||||
return "%"
|
||||
|
||||
case .blueReader:
|
||||
return "%"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,6 +330,10 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
|
||||
case .Blucon:
|
||||
return false
|
||||
|
||||
case .blueReader:
|
||||
return false
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
import Foundation
|
||||
import os
|
||||
import CoreBluetooth
|
||||
|
||||
class CGMBlueReaderTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
/// service to be discovered
|
||||
let CBUUID_Service_BlueReader: String = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
/// receive characteristic
|
||||
let CBUUID_ReceiveCharacteristic_BlueReader: String = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
/// write characteristic
|
||||
let CBUUID_WriteCharacteristic_BlueReader: String = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
/// will be used to pass back bluetooth and cgm related events
|
||||
private(set) weak var cgmTransmitterDelegate: CGMTransmitterDelegate?
|
||||
|
||||
/// for trace
|
||||
private let log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryCGMBlueReader)
|
||||
|
||||
/// used as parameter in call to cgmTransmitterDelegate.cgmTransmitterInfoReceived, when there's no glucosedata to send
|
||||
var emptyArray: [GlucoseData] = []
|
||||
|
||||
// MARK: - Initialization
|
||||
/// - parameters:
|
||||
/// - address: if already connected before, then give here the address that was received during previous connect, if not give nil
|
||||
/// - name : if already connected before, then give here the name that was received during previous connect, if not give nil
|
||||
init(address:String?, name: String?, delegate:CGMTransmitterDelegate) {
|
||||
|
||||
// assign addressname and name or expected devicename
|
||||
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "blueReader")
|
||||
if let address = address {
|
||||
newAddressAndName = BluetoothTransmitter.DeviceAddressAndName.alreadyConnectedBefore(address: address, name: name)
|
||||
}
|
||||
|
||||
// assign CGMTransmitterDelegate
|
||||
cgmTransmitterDelegate = delegate
|
||||
|
||||
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_BlueReader)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_BlueReader, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_BlueReader, startScanningAfterInit: CGMTransmitterType.blueReader.startScanningAfterInit())
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
|
||||
}
|
||||
|
||||
// MARK: - BluetoothTransmitterDelegate functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
trace("in peripheral didUpdateValueFor", log: log, type: .info)
|
||||
|
||||
if let value = characteristic.value {
|
||||
|
||||
guard let valueAsString = String(bytes: value, encoding: .utf8) else {
|
||||
trace(" failed to convert value to string", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
trace(" value = %{public}@", log: log, type: .info, valueAsString)
|
||||
|
||||
//find indexes of " "
|
||||
let indexesOfSplitter = valueAsString.indexes(of: " ")
|
||||
|
||||
// second field is the battery level, there should be at least one space
|
||||
guard indexesOfSplitter.count >= 1 else {
|
||||
trace(" there's less than 1 space", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
// get first field, this is rawdata
|
||||
let rawDataAsString = String(valueAsString[valueAsString.startIndex..<indexesOfSplitter[0]])
|
||||
|
||||
// convert rawDataAsString to double and stop if this fails
|
||||
guard let rawDataAsDouble = rawDataAsString.toDouble() else {
|
||||
trace(" failed to convert rawDataAsString to double", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
// if there's more than one field, then the second field is battery level
|
||||
// there could be 2 fields or more
|
||||
//var batteryLevelAsString:String? = nil
|
||||
|
||||
//if indexesOfSplitter.count == 1 {// there's two fields
|
||||
// batteryLevelAsString = String(valueAsString[valueAsString.index(after: indexesOfSplitter[0])..<valueAsString.endIndex])
|
||||
//} else {// there's more than 2 fields
|
||||
// batteryLevelAsString = String(valueAsString[valueAsString.index(after: indexesOfSplitter[0])..<indexesOfSplitter[1]])
|
||||
//}
|
||||
|
||||
var transMitterBatteryInfo:TransmitterBatteryInfo? = nil
|
||||
//if let batteryLevelAsString = batteryLevelAsString, let batteryLevelAsInt = Int(batteryLevelAsString) {
|
||||
// transMitterBatteryInfo = TransmitterBatteryInfo.percentage(percentage: batteryLevelAsInt)
|
||||
//}
|
||||
|
||||
// send to delegate
|
||||
var glucoseDataArray = [GlucoseData(timeStamp: Date(), glucoseLevelRaw: rawDataAsDouble)]
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &glucoseDataArray, transmitterBatteryInfo: transMitterBatteryInfo, sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
} else {
|
||||
trace(" value is nil, no further processing", log: log, type: .error)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: CGMTransmitter protocol functions
|
||||
|
||||
/// to ask pairing - empty function because Bubble doesn't need pairing
|
||||
///
|
||||
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
|
||||
func initiatePairing() {}
|
||||
|
||||
/// to ask transmitter reset - empty function because Bubble doesn't support reset
|
||||
///
|
||||
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
|
||||
func reset(requested:Bool) {}
|
||||
|
||||
/// this transmitter does not support oopWeb
|
||||
func setWebOOPEnabled(enabled: Bool) {
|
||||
}
|
||||
|
||||
/// this transmitter does not support oop web
|
||||
func setWebOOPSiteAndToken(oopWebSite: String, oopWebToken: String) {}
|
||||
|
||||
}
|
|
@ -697,6 +697,9 @@ final class RootViewController: UIViewController {
|
|||
case .Droplet1:
|
||||
cgmTransmitter = CGMDroplet1Transmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, delegate: self)
|
||||
|
||||
case .blueReader:
|
||||
cgmTransmitter = CGMBlueReaderTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, delegate: self)
|
||||
|
||||
}
|
||||
|
||||
// assign calibrator
|
||||
|
@ -704,7 +707,7 @@ final class RootViewController: UIViewController {
|
|||
|
||||
case .dexcomG4, .dexcomG5, .dexcomG6:
|
||||
calibrator = DexcomCalibrator()
|
||||
case .miaomiao, .GNSentry, .Blucon, .Bubble, .Droplet1:
|
||||
case .miaomiao, .GNSentry, .Blucon, .Bubble, .Droplet1, .blueReader:
|
||||
// for all transmitters used with Libre1, calibrator is either NoCalibrator or Libre1Calibrator, depending if oopWeb is supported by the transmitter and on value of webOOPEnabled in settings
|
||||
calibrator = RootViewController.getCalibrator(transmitterType: selectedTransmitterType, webOOPEnabled: UserDefaults.standard.webOOPEnabled)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue