bluereader, not tested, battery level not supported

This commit is contained in:
Johan Degraeve 2019-11-01 14:07:15 +01:00
parent 9b6b638ad6
commit 81128ff7ee
6 changed files with 192 additions and 1 deletions

View File

@ -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 */,

View File

@ -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

View File

@ -82,6 +82,9 @@ enum ConstantsLog {
/// droplet 1
static let categoryCGMDroplet1 = "categoryCGMDroplet1"
/// bluereader
static let categoryCGMBlueReader = "categoryCGMBlueReader"
/// LibreOOPClient
static let categoryLibreOOPClient = "categoryLibreOOPClient"

View File

@ -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
}
}
}

View File

@ -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) {}
}

View File

@ -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)
}