Skip to content
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ dependencies {
":pump:omnipod:common",
":pump:omnipod:eros",
":pump:omnipod:dash",
":pump:rileylink"
":pump:rileylink",
":pump:carelevo"
)
pumpDependencies.forEach {
"fullImplementation"(project(it))
Expand Down Expand Up @@ -259,4 +260,3 @@ if (!gitAvailable()) {
if (isMaster() && !allCommitted()) {
throw GradleException("There are uncommitted changes. Clone sources again as described in wiki and do not allow gradle update")
}

2 changes: 2 additions & 0 deletions app/src/withPumps/kotlin/app/aaps/di/PumpDriversModule.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.aaps.di

import app.aaps.pump.carelevo.di.CarelevoModule
import app.aaps.pump.common.di.PumpCommonModule
import app.aaps.pump.common.di.RileyLinkModule
import app.aaps.pump.diaconn.di.DiaconnG8Module
Expand Down Expand Up @@ -30,6 +31,7 @@ import info.nightscout.pump.combov2.di.ComboV2Module
MedtrumModule::class,
EquilModule::class,
EquilModules::class,
CarelevoModule::class
]
)
@InstallIn(SingletonComponent::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum class ManufacturerType(val description: String) {
Ypsomed("Ypsomed"),
G2e("G2e"),
Eoflow("Eoflow"),
CareMedi("CareMedi"),
Equil("Equil");

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ enum class PumpCapability {
DiaconnCapabilities(arrayOf(Capability.Bolus, Capability.ExtendedBolus, Capability.TempBasal, Capability.BasalProfileSet, Capability.Refill, Capability.ReplaceBattery, Capability.TDD, Capability.ManualTDDLoad)), //
EopatchCapabilities(arrayOf(Capability.Bolus, Capability.ExtendedBolus, Capability.TempBasal, Capability.BasalProfileSet, Capability.BasalRate30min)),
MedtrumCapabilities(arrayOf(Capability.Bolus, Capability.TempBasal, Capability.BasalProfileSet, Capability.BasalRate30min, Capability.TDD)), // Technically the pump supports ExtendedBolus, but not implemented (yet)
;
CarelevoCapabilities(arrayOf(Capability.Bolus, Capability.ExtendedBolus, Capability.TempBasal, Capability.BasalProfileSet, Capability.BasalRate30min));

var children: ArrayList<Capability> = ArrayList()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,26 @@ enum class PumpType(
model = "untested",
parent = MEDTRUM_NANO
),

CAREMEDI_CARELEVO(
description = "Carelevo",
manufacturer = ManufacturerType.CareMedi,
model = "Carelevo",
bolusSize = 0.05,
specialBolusSize = null,
extendedBolusSettings = DoseSettings(0.05, 30, 8 * 60, 0.05, 25.0),
pumpTempBasalType = PumpTempBasalType.Absolute,
tbrSettings = DoseSettings(0.05, 30, 12 * 60, 0.0, 15.0),
specialBasalDurations = arrayOf(Capability.BasalRate_Duration30minAllowed),
baseBasalMinValue = 0.05,
baseBasalMaxValue = 15.0,
baseBasalStep = 0.05,
baseBasalSpecialSteps = null,
pumpCapability = PumpCapability.CarelevoCapabilities,
isPatchPump = true,
maxReservoirReading = 300,
source = Source.Carelevo
),
EQUIL(
description = "Equil",
manufacturer = ManufacturerType.Equil,
Expand Down Expand Up @@ -511,7 +531,8 @@ enum class PumpType(
MDI,
VirtualPump,
Unknown,
EQuil
EQuil,
Carelevo
}

companion object {
Expand Down
2 changes: 2 additions & 0 deletions core/data/src/main/kotlin/app/aaps/core/data/ue/Sources.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ enum class Sources {
Garmin,
Scene, //From Scene activation
Database, // for PersistenceLayer

Carelevo,
Unknown //if necessary
;
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ enum class NotificationId(
// Pump — Dana emulator
PUMP_EMULATOR_DISPLAY(1001, INFO, PUMP),

// Pump — Carelevo
CARELEVO_PATCH_ALERT(150, URGENT, PUMP, allowMultiple = true),

// CGM
BG_READINGS_MISSED(27, URGENT, CGM),

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package app.aaps.core.ui.compose.icons

import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathFillType
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

/**
* Icon for CareLevo Pump Plugin.
*
* Single-color design using NonZero winding to create holes:
* CW outer body → filled border frame
* CCW inner panel → transparent window
* CCW connector dots (in border) → transparent holes
* CW lens circle → ring fill
* CCW lens center → transparent center of ring
* CW text bars → filled bars inside window
*
* Works correctly with any tint color (no multi-color tricks).
*/
val IcPluginCarelevo: ImageVector by lazy {
ImageVector.Builder(
name = "IcPluginCarelevo",
defaultWidth = 48.dp,
defaultHeight = 48.dp,
viewportWidth = 24f,
viewportHeight = 24f
).apply {

// ── Combined body + all winding-based cutouts/fills ───────────────────
path(
fill = SolidColor(Color.Black),
fillAlpha = 1.0f,
stroke = null,
strokeAlpha = 1.0f,
strokeLineWidth = 1.0f,
strokeLineCap = StrokeCap.Butt,
strokeLineJoin = StrokeJoin.Miter,
strokeLineMiter = 1.0f,
pathFillType = PathFillType.NonZero
) {
// ── 1. Outer device body (CW) ─ winding = +1 ──────────────────────
moveTo(5.9f, 4.5f)
lineTo(18.1f, 4.5f)
curveTo(20.5f, 4.5f, 22.5f, 6.5f, 22.5f, 8.9f)
lineTo(22.5f, 15.1f)
curveTo(22.5f, 17.5f, 20.5f, 19.5f, 18.1f, 19.5f)
lineTo(5.9f, 19.5f)
curveTo(3.5f, 19.5f, 1.5f, 17.5f, 1.5f, 15.1f)
lineTo(1.5f, 8.9f)
curveTo(1.5f, 6.5f, 3.5f, 4.5f, 5.9f, 4.5f)
close()

// ── 2. Inner panel (CCW) ─ cancels to 0 → transparent window ──────
// Start TL, go DOWN first (CCW in screen-Y-down coords)
moveTo(5.8f, 6.5f)
curveTo(4.58f, 6.5f, 3.6f, 7.48f, 3.6f, 8.7f)
lineTo(3.6f, 15.3f)
curveTo(3.6f, 16.52f, 4.58f, 17.5f, 5.8f, 17.5f)
lineTo(18.2f, 17.5f)
curveTo(19.42f, 17.5f, 20.4f, 16.52f, 20.4f, 15.3f)
lineTo(20.4f, 8.7f)
curveTo(20.4f, 7.48f, 19.42f, 6.5f, 18.2f, 6.5f)
close()

// ── 3. Connector dot holes (CCW, r=0.4) ─ transparent holes ───────
// isPositiveArc=false → CCW arc → creates hole
// Top connector (center 6.9, 5.8)
moveTo(7.3f, 5.8f)
arcToRelative(0.4f, 0.4f, 0f, isMoreThanHalf = true, isPositiveArc = false, dx1 = -0.8f, dy1 = 0f)
arcToRelative(0.4f, 0.4f, 0f, isMoreThanHalf = true, isPositiveArc = false, dx1 = 0.8f, dy1 = 0f)
// Bottom connector (center 6.9, 18.3)
moveTo(7.3f, 18.3f)
arcToRelative(0.4f, 0.4f, 0f, isMoreThanHalf = true, isPositiveArc = false, dx1 = -0.8f, dy1 = 0f)
arcToRelative(0.4f, 0.4f, 0f, isMoreThanHalf = true, isPositiveArc = false, dx1 = 0.8f, dy1 = 0f)
// Right connector (center 21.5, 12.0)
moveTo(21.9f, 12.0f)
arcToRelative(0.4f, 0.4f, 0f, isMoreThanHalf = true, isPositiveArc = false, dx1 = -0.8f, dy1 = 0f)
arcToRelative(0.4f, 0.4f, 0f, isMoreThanHalf = true, isPositiveArc = false, dx1 = 0.8f, dy1 = 0f)

// ── 4. CARELEVO text bars (CW rects) ─ +1 → fills inside window ───
// Go RIGHT first from TL (CW in screen-Y-down coords)
moveTo(13.2f, 10.7f)
lineTo(19.5f, 10.7f)
lineTo(19.5f, 11.2f)
lineTo(13.2f, 11.2f)
close()
moveTo(13.2f, 11.75f)
lineTo(18.3f, 11.75f)
lineTo(18.3f, 12.25f)
lineTo(13.2f, 12.25f)
close()
moveTo(13.2f, 12.8f)
lineTo(19.5f, 12.8f)
lineTo(19.5f, 13.3f)
lineTo(13.2f, 13.3f)
close()
}

// ── Lens arc – 300° open arc, gap on right (C보다 조금 더 길게) ──────────
// Center (10.1, 12.0), r = 1.75
// Start: 30° above right → (11.62, 11.13)
// End : 30° below right → (11.62, 12.88)
// Long CCW arc (300°) going up → left → down
path(
fill = SolidColor(Color.Transparent),
fillAlpha = 0f,
stroke = SolidColor(Color.Black),
strokeAlpha = 1.0f,
strokeLineWidth = 0.85f,
strokeLineCap = StrokeCap.Round,
strokeLineJoin = StrokeJoin.Round,
strokeLineMiter = 1.0f
) {
moveTo(11.62f, 11.13f)
arcToRelative(1.75f, 1.75f, 0f, isMoreThanHalf = true, isPositiveArc = false, dx1 = 0f, dy1 = 1.75f)
}

}.build()
}

@Preview(showBackground = true, backgroundColor = 0xFFFFFFFF)
@Composable
private fun IcPluginCarelevoPreview() {
Icon(
imageVector = IcPluginCarelevo,
contentDescription = null,
modifier = Modifier
.padding(8.dp)
.size(48.dp),
tint = Color.Unspecified
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ data class UserEntry(
BgFragment,
Garmin,
Database, //for PersistenceLayer

Carelevo,
Unknown, //if necessary
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ data class InterfaceIDs @Ignore constructor(
MEDTRUM_UNTESTED,
USER,
CACHE,
CARELEVO,
EQUIL;

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fun InterfaceIDs.PumpType.fromDb(): PumpType =
InterfaceIDs.PumpType.MEDTRUM_UNTESTED -> PumpType.MEDTRUM_UNTESTED
InterfaceIDs.PumpType.CACHE -> PumpType.CACHE
InterfaceIDs.PumpType.EQUIL -> PumpType.EQUIL
InterfaceIDs.PumpType.CARELEVO -> PumpType.CAREMEDI_CARELEVO
}

fun PumpType.toDb(): InterfaceIDs.PumpType =
Expand Down Expand Up @@ -83,5 +84,6 @@ fun PumpType.toDb(): InterfaceIDs.PumpType =
PumpType.MEDTRUM_UNTESTED -> InterfaceIDs.PumpType.MEDTRUM_UNTESTED
PumpType.CACHE -> InterfaceIDs.PumpType.CACHE
PumpType.EQUIL -> InterfaceIDs.PumpType.EQUIL
PumpType.CAREMEDI_CARELEVO -> InterfaceIDs.PumpType.CARELEVO

}
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ fun UserEntry.Sources.fromDb(): Sources =
UserEntry.Sources.Garmin -> Sources.Garmin
UserEntry.Sources.Scene -> Sources.Scene
UserEntry.Sources.Database -> Sources.Database
UserEntry.Sources.Carelevo -> Sources.Carelevo
UserEntry.Sources.Unknown -> Sources.Unknown
}

Expand Down Expand Up @@ -174,6 +175,7 @@ fun Sources.toDb(): UserEntry.Sources =
Sources.Scene -> UserEntry.Sources.Scene
Sources.Database -> UserEntry.Sources.Database
Sources.Insulin -> UserEntry.Sources.Insulin
Sources.Carelevo -> UserEntry.Sources.Carelevo
Sources.Unknown -> UserEntry.Sources.Unknown
}

Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import app.aaps.core.ui.compose.icons.IcPatchPump
import app.aaps.core.ui.compose.icons.IcPluginAutomation
import app.aaps.core.ui.compose.icons.IcPluginAutotune
import app.aaps.core.ui.compose.icons.IcPluginCarelevo
import app.aaps.core.ui.compose.icons.IcPluginCombo
import app.aaps.core.ui.compose.icons.IcPluginConfigBuilder
import app.aaps.core.ui.compose.icons.IcPluginDanaI
Expand Down Expand Up @@ -96,7 +97,7 @@
private val decimalFormatter: DecimalFormatter
) : UserEntryPresentationHelper {

override fun icon(source: Sources): ImageVector = when (source) {

Check warning on line 100 in implementation/src/main/kotlin/app/aaps/implementation/userEntry/UserEntryPresentationHelperImpl.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Reduce the number of when branches from 84 to at most 30.

See more on https://sonarcloud.io/project/issues?id=nightscout_AndroidAPS&issues=AZ2xiyAn1bH6TsjJaUEj&open=AZ2xiyAn1bH6TsjJaUEj&pullRequest=4742
Sources.Aaps -> IcAaps
Sources.Actions -> IcAction
Sources.Aidex -> IcXDrip
Expand All @@ -109,6 +110,7 @@
Sources.BgFragment -> IcAaps
Sources.CalibrationDialog -> IcCalibration
Sources.CarbDialog -> IcCarbs
Sources.Carelevo -> IcPluginCarelevo
Sources.Combo -> IcPluginCombo
Sources.ConcentrationDialog -> IcPluginInsulin
Sources.ConfigBuilder -> IcPluginConfigBuilder
Expand Down Expand Up @@ -267,6 +269,7 @@
Sources.Wear -> ElementType.AAPS.color()
Sources.WizardDialog -> ElementType.BOLUS_WIZARD.color()
Sources.Xdrip -> ElementType.CGM_XDRIP.color()
Sources.Carelevo -> ElementType.PUMP.color()
}

override fun listToPresentationString(list: List<ValueWithUnit>) =
Expand Down
40 changes: 40 additions & 0 deletions pump/carelevo/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.ksp)
alias(libs.plugins.hilt)
id("android-module-dependencies")
id("test-module-dependencies")
id("jacoco-module-dependencies")
}

android {
namespace = "app.aaps.pump.carelevo"

buildFeatures {
compose = true
}
}

dependencies {
implementation(project(":core:data"))
implementation(project(":core:interfaces"))
implementation(project(":core:utils"))
implementation(project(":core:ui"))
implementation(project(":core:keys"))
implementation(libs.androidx.compose.ui.tooling.preview)
debugImplementation(libs.androidx.compose.ui.tooling)

api(libs.com.google.guava)
implementation(libs.androidx.lifecycle.process)
api(libs.io.reactivex.rxjava3.rxandroid)
api(libs.com.polidea.rxandroidble3)
api(libs.com.jakewharton.rx3.replaying.share)
implementation(libs.com.google.android.material)

implementation(libs.com.google.dagger.hilt.android)
implementation(libs.androidx.hilt.navigation.compose)
ksp(libs.com.google.dagger.compiler)
ksp(libs.com.google.dagger.hilt.compiler)
ksp(libs.com.google.dagger.android.processor)
}
11 changes: 11 additions & 0 deletions pump/carelevo/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?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 />

</manifest>
Loading