Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a62d05c
test
Dec 20, 2025
1ed863b
test
Dec 20, 2025
4e53e2c
test
Dec 20, 2025
4a22096
test
Dec 20, 2025
4bb244e
test
Dec 20, 2025
5b6e726
test
Dec 20, 2025
1db9785
wip: start eversense project
bastiaanv Dec 29, 2025
2b79700
chore: fix syntax error
bastiaanv Dec 29, 2025
82b1d8f
moving changes
Dec 29, 2025
7c4509e
wip: start E3 connection
bastiaanv Dec 29, 2025
8633bf1
Merge branch 'feat/eversense' into dev
bastiaanv Dec 30, 2025
9bf1ab7
fix: merge conflicts
bastiaanv Dec 30, 2025
aaad1e7
fix: remote device & storage
bastiaanv Dec 30, 2025
905dce5
Merge pull request #2 from bastiaanv/dev
n0rb33r7 Dec 30, 2025
9359323
wip: start E3 glucose reading
bastiaanv Dec 30, 2025
7746524
feat: time syncing & recent glucose & inject glucose to AAPS
bastiaanv Jan 1, 2026
5cf3d46
feat: Add logger & onStateChanged
bastiaanv Jan 4, 2026
7ca5c60
wip: transmitter settings
bastiaanv Jan 4, 2026
9132e41
feat: finish transmitter settings
bastiaanv Jan 5, 2026
5221710
opt: Optimize current glucose reading
bastiaanv Jan 5, 2026
86e66b5
feat: add UI with basic information
bastiaanv Jan 5, 2026
2c74623
Merge pull request #3 from bastiaanv/dev
n0rb33r7 Jan 6, 2026
aba7d0f
chore: cleanup
bastiaanv Jan 8, 2026
c5bb8d3
chore: cleanup
bastiaanv Jan 8, 2026
066e4c1
Merge pull request #4 from bastiaanv/dev
n0rb33r7 Jan 8, 2026
048dc3d
chore: cleanup
bastiaanv Jan 9, 2026
6a5e139
Merge pull request #5 from bastiaanv/dev
bastiaanv Jan 9, 2026
2e481ea
chore: cleanup
bastiaanv Jan 9, 2026
e544a40
Merge branch 'n0rb33r7:dev' into dev
bastiaanv Jan 9, 2026
d5a075e
Merge pull request #6 from bastiaanv/dev
bastiaanv Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion app/src/main/kotlin/app/aaps/di/PluginsListModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import app.aaps.plugins.smoothing.AvgSmoothingPlugin
import app.aaps.plugins.smoothing.ExponentialSmoothingPlugin
import app.aaps.plugins.smoothing.NoSmoothingPlugin
import app.aaps.plugins.source.DexcomPlugin
import app.aaps.plugins.source.EversensePlugin
import app.aaps.plugins.source.GlimpPlugin
import app.aaps.plugins.source.GlunovoPlugin
import app.aaps.plugins.source.IntelligoPlugin
Expand Down Expand Up @@ -390,7 +391,13 @@ abstract class PluginsListModule {
@IntoMap
@IntKey(410)
abstract fun bindNSClientSourcePlugin(plugin: NSClientSourcePlugin): PluginBase


@Binds
@AllConfigs
@IntoMap
@IntKey(415)
abstract fun bindEversenseSourcePlugin(plugin: EversensePlugin): PluginBase

@Binds
@AllConfigs
@IntoMap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ enum class SourceSensor(val text: String) {
OTTAI("Ottai"),
SIBIONIC("SI App"),
SINO("Sino App"),
EVERSENSE("Eversense"),
EVERSENSE_E3("Eversense E3"),
EVERSENSE_365("Eversense 365"),
AIDEX("GlucoRx Aidex"),
SYAI_TAG("Syai Tag"),
RANDOM("Random"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ data class GlucoseValue(
GLUNOVO_NATIVE,
INTELLIGO_NATIVE,
MM_600_SERIES,
EVERSENSE,
EVERSENSE_E3,
EVERSENSE_365,
AIDEX,
RANDOM,
UNKNOWN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ fun GlucoseValue.SourceSensor.fromDb(): SourceSensor =
GlucoseValue.SourceSensor.GLUNOVO_NATIVE -> SourceSensor.GLUNOVO_NATIVE
GlucoseValue.SourceSensor.INTELLIGO_NATIVE -> SourceSensor.INTELLIGO_NATIVE
GlucoseValue.SourceSensor.MM_600_SERIES -> SourceSensor.MM_600_SERIES
GlucoseValue.SourceSensor.EVERSENSE -> SourceSensor.EVERSENSE
GlucoseValue.SourceSensor.EVERSENSE_E3 -> SourceSensor.EVERSENSE_E3
GlucoseValue.SourceSensor.EVERSENSE_365 -> SourceSensor.EVERSENSE_365
GlucoseValue.SourceSensor.AIDEX -> SourceSensor.AIDEX
GlucoseValue.SourceSensor.RANDOM -> SourceSensor.RANDOM
GlucoseValue.SourceSensor.UNKNOWN -> SourceSensor.UNKNOWN
Expand Down Expand Up @@ -73,7 +74,8 @@ fun SourceSensor.toDb(): GlucoseValue.SourceSensor =
SourceSensor.GLUNOVO_NATIVE -> GlucoseValue.SourceSensor.GLUNOVO_NATIVE
SourceSensor.INTELLIGO_NATIVE -> GlucoseValue.SourceSensor.INTELLIGO_NATIVE
SourceSensor.MM_600_SERIES -> GlucoseValue.SourceSensor.MM_600_SERIES
SourceSensor.EVERSENSE -> GlucoseValue.SourceSensor.EVERSENSE
SourceSensor.EVERSENSE_E3 -> GlucoseValue.SourceSensor.EVERSENSE_E3
SourceSensor.EVERSENSE_365 -> GlucoseValue.SourceSensor.EVERSENSE_365
SourceSensor.AIDEX -> GlucoseValue.SourceSensor.AIDEX
SourceSensor.RANDOM -> GlucoseValue.SourceSensor.RANDOM
SourceSensor.UNKNOWN -> GlucoseValue.SourceSensor.UNKNOWN
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk
kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }

kotlinx-serialization-bom = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-bom", version.ref = "kotlinx-serialization" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
kotlinx-serialization-protobuf = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-protobuf" }
kotlinx-serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core" }

Expand Down
1 change: 1 addition & 0 deletions plugins/eversense/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
20 changes: 20 additions & 0 deletions plugins/eversense/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.ksp)

id("kotlin-android")
id("kotlinx-serialization")
id("android-module-dependencies")
}

android {
namespace = "com.nightscout.eversense"
}

dependencies {
api(libs.androidx.core)
api(libs.kotlinx.serialization.json)

api(libs.org.slf4j.api)
api(libs.com.github.tony19.logback.android)
}
Empty file.
21 changes: 21 additions & 0 deletions plugins/eversense/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
12 changes: 12 additions & 0 deletions plugins/eversense/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

<application>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package com.nightscout.eversense

import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanSettings
import android.content.Context
import android.content.SharedPreferences
import android.os.ParcelUuid
import com.nightscout.eversense.callbacks.EversenseScanCallback
import com.nightscout.eversense.callbacks.EversenseWatcher
import com.nightscout.eversense.models.EversenseState
import com.nightscout.eversense.models.EversenseTransmitterSettings
import com.nightscout.eversense.packets.EversenseE3Communicator
import kotlinx.serialization.json.Json

class EversenseCGMPlugin {
private var context: Context? = null

private var bluetoothManager: BluetoothManager? = null
private var preferences: SharedPreferences? = null
private var gattCallback: EversenseGattCallback? = null

private var scanner: EversenseScanner? = null
var watchers: List<EversenseWatcher> = listOf()

fun setContext(context: Context, loggingEnabled: Boolean) {
this.context = context
EversenseLogger.instance.enableLogging(loggingEnabled)

val preference = context.getSharedPreferences(TAG, Context.MODE_PRIVATE)

bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
preferences = preference
gattCallback = EversenseGattCallback(this, preference)
}

fun addWatcher(watcher: EversenseWatcher) {
this.watchers += watcher
}

fun isConnected(): Boolean {
val gattCallback = this.gattCallback ?:run {
return false
}

return gattCallback.isConnected()
}

fun getCurrentState(): EversenseState? {
val preferences = preferences ?:run {
EversenseLogger.error(TAG, "No preferences available. Make sure setContext has been called")
return null
}

val stateJson = preferences.getString(StorageKeys.STATE, null) ?: "{}"
return Json.decodeFromString<EversenseState>(stateJson)
}

@SuppressLint("MissingPermission")
fun startScan(callback: EversenseScanCallback) {
val bluetoothScanner = this.bluetoothManager?.adapter?.bluetoothLeScanner ?:run {
EversenseLogger.error(TAG, "No bluetooth manager available. Make sure setContext has been called")
return
}

scanner = EversenseScanner(callback)
val filters = listOf(
ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(EversenseGattCallback.serviceUUID)).build()
)
val settings = ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build()
bluetoothScanner.startScan(filters, settings, scanner)
}

@SuppressLint("MissingPermission")
fun connect(device: BluetoothDevice?): Boolean {
val bluetoothManager = this.bluetoothManager ?:run {
EversenseLogger.error(TAG, "No bluetooth manager available. Make sure setContext has been called")
return false
}

val gattCallback = this.gattCallback ?:run {
EversenseLogger.error(TAG, "No gattCallback available. Make sure setContext has been called")
return false
}

if (scanner != null) {
bluetoothManager.adapter.bluetoothLeScanner.stopScan(scanner)
}

if (gattCallback.isConnected()) {
EversenseLogger.info(TAG, "Already connected!")
return true
}

if (device != null) {
EversenseLogger.info(TAG, "Connecting to ${device.name}")
device.connectGatt(context, true, gattCallback)
return true
}

val address = preferences?.getString(StorageKeys.REMOTE_DEVICE_KEY, null) ?:run {
EversenseLogger.error(TAG, "Remote device not stored. Make sure you've connected once and bonded to this device")
return false
}

val remoteDevice = bluetoothManager.adapter.getRemoteDevice(address) ?:run {
EversenseLogger.error(TAG, "Remote device not found. Make sure you've connected once and bonded to this device")
return false
}

remoteDevice.connectGatt(context, true, gattCallback)
return true
}

fun writeSettings(settings: EversenseTransmitterSettings): Boolean {
val preferences = preferences ?:run {
EversenseLogger.error(TAG, "No preferences available. Make sure setContext has been called")
return false
}

val gattCallback = this.gattCallback ?:run {
EversenseLogger.error(TAG, "No gattCallback available. Make sure transmitter is connected before writing settings")
return false
}

if (!gattCallback.isConnected()) {
EversenseLogger.error(TAG, "Transmitter is not connected...")
return false
}

return EversenseE3Communicator.writeSettings(gattCallback, preferences, settings)
}

companion object {
private const val TAG = "EversenseCGMManager"

val instance:EversenseCGMPlugin by lazy {
EversenseCGMPlugin()
}
}
}
Loading
Loading