Kohlenhydrate aus CarbCam direkt in den AAPS 3.4.x.x/aaps4/iAPS Bolus-Wizard übernehmen
Stand: AAPS 3.4.2.2 branch. AAPS 4 (DEV), iAPS
Worum geht’s
Wer Kohlenhydrate per Foto schätzt (CarbCam) oder aus einer Lebensmittel-Datenbank zieht, muss den Wert bisher abtippen oder über Nightscout-Treatments umweglos hineinpumpen. Beides ist umständlich. Der hier beschriebene Patch fügt AAPS einen kleinen, definierten Eingang hinzu:
Eine andere App wie z.b. CarbCam sendet einen Android Intent an AAPS mit Aktion info.nightscout.androidaps.action.OPEN_BOLUS_WIZARD und einem Carbs-Wert. AAPS öffnet daraufhin denselben Bolus-Wizard wie bei manueller Eingabe, mit dem Carbs-Feld bereits ausgefüllt. Der Benutzer prüft, drückt OK, sieht den Standard-AAPS-Bestätigungsdialog und gibt den Bolus frei. Es gibt keine Möglichkeit, Insulin ohne Bestätigung abzugeben.
CarbCam (de.be10.carbcam)
│
│ Intent: OPEN_BOLUS_WIZARD
│ extras: carbs=42, notes="Pizza Margherita"
▼
WizardLaunchActivity (exported, Caller-Whitelist)
│
│ prüft: callingPackage, Range 1–80
│ leitet weiter: open_wizard_carbs, open_wizard_notes
▼
MainActivity (singleTask)
│
│ liest Extras, zeigt WizardDialog
▼
WizardDialog (Standard-Bolus-Wizard, vorbefüllt)
│
│ Benutzer bestätigt
▼
AAPS-Standard-Bestätigungsdialog → Bolus
Sicherheits-Design
Vier Schichten, alle aktiv:
- Whitelist — Nur explizit erlaubte Caller-Packages (z.B.
de.be10.carbcam) können den Wizard öffnen. Andere Apps werden vom Launcher kommentarlos abgewiesen.
- Range-Check — Carbs außerhalb 1–80 g werden verworfen. Wer mehr braucht, hebt den Wert anschließend im Wizard manuell an.
- Kein automatischer Bolus — Der Patch öffnet nur den Wizard. Der Benutzer durchläuft denselben Bestätigungsflow wie bei manueller Eingabe.
- Source-Anzeige — Der
source-Parameter erscheint im Wizard-Notes-Feld („via CarbCam“), wird aber nicht als Vertrauensbeweis gewertet.
Voraussetzungen
- AAPS 3.4.2.2 branch, lokal oder GitHub geklont und mit Android Studio oder BrowserBuild baubar
- Kotlin/Android Grundkenntnisse (vi reicht zum Editieren)
WICHTIG! Falls du eigene Anpassungen in AAPS gemacht hast, können die Zeilennummer anders sein.
Patchfiles für iaps (ungetestet), AndroidAPS 3.4.2.2 und AAPS DEV 4:
https://github.com/zehnBE/aaps3.4.2.2-carbcam-patches/blob/main/README.md
Patch — 5 Änderungen
1. Neue Datei anlegen
Datei: app/src/main/kotlin/app/aaps/activities/WizardLaunchActivity.kt
mit folgendem Inhalt:
package app.aaps.activities
import android.content.Intent
import android.os.Bundle
import app.aaps.MainActivity
import app.aaps.plugins.configuration.activities.DaggerAppCompatActivityWithResult
class WizardLaunchActivity : DaggerAppCompatActivityWithResult() {
companion object {
const val EXTRA_CARBS = "carbs"
const val EXTRA_NOTES = "notes"
const val EXTRA_SOURCE = "source"
// Whitelist: nur CarbCam darf den Wizard externe öffnen
private val ALLOWED_CALLERS = setOf(
"de.be10.carbcam",
"de.be10.carbcam.debug"
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val caller = callingPackage ?: referrer?.host
if (caller !in ALLOWED_CALLERS) {
finish()
return
}
val carbs = intent.getIntExtra(EXTRA_CARBS, 0)
val notes = intent.getStringExtra(EXTRA_NOTES) ?: ""
if (carbs <= 0 || carbs > 80) {
finish()
return
}
startActivity(Intent(this, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP)
putExtra("open_wizard_carbs", carbs)
putExtra("open_wizard_notes", notes)
})
finish()
}
}
2. AndroidManifest.xml ergänzen
Datei: app/src/main/AndroidManifest.xml
Innerhalb des <application>-Blocks, neben den anderen Activities:
<activity
android:name="app.aaps.activities.WizardLaunchActivity"
android:exported="true"
android:excludeFromRecents="true"
android:launchMode="singleInstance"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="info.nightscout.androidaps.action.OPEN_BOLUS_WIZARD" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
exported="true" ist nötig, weil eine andere App die Activity ansprechen können muss. excludeFromRecents und singleInstance sorgen dafür, dass die Launcher-Activity im Recents-Switcher nicht auftaucht und keine eigene Task-History anlegt.
3. Dagger-Registrierung
Datei: app/src/main/kotlin/app/aaps/di/ActivitiesModule.kt
Import ergänzen:
import app.aaps.activities.WizardLaunchActivity
Innerhalb der ActivitiesModule-Klasse eine Zeile dazu:
@ContributesAndroidInjector
abstract fun contributesWizardLaunchActivity(): WizardLaunchActivity
Ohne diesen Eintrag bekommt die Activity beim Start IllegalArgumentException: No injector factory bound for Class.
4. MainActivity erweitern
Datei: app/src/main/kotlin/app/aaps/MainActivity.kt
Am Ende von onCreate() einfügen:
handleExternalWizardIntent(intent)
Neue Override und private Methode in derselben Klasse ergänzen:
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleExternalWizardIntent(intent)
}
private fun handleExternalWizardIntent(intent: Intent?) {
val carbs = intent?.getIntExtra("open_wizard_carbs", 0) ?: 0
if (carbs <= 0) return
val notes = intent.getStringExtra("open_wizard_notes") ?: ""
// Extras "verbrauchen", damit sie beim nächsten Lifecycle nicht erneut feuern
intent.removeExtra("open_wizard_carbs")
intent.removeExtra("open_wizard_notes")
val wizard = app.aaps.ui.dialogs.WizardDialog()
wizard.arguments = Bundle().apply {
putDouble("carbs_input", carbs.toDouble())
putString("notes_input", notes)
}
wizard.show(supportFragmentManager, "WizardDialog")
}
Den vollqualifizierten Pfad app.aaps.ui.dialogs.WizardDialog nicht durch app.aaps.plugins.main.dialogs.WizardDialog ersetzen — der WizardDialog im aktuellen dev-Branch liegt im Modul :ui, nicht in :plugins:main.
5. WizardDialog argumentfähig machen (optional)
Datei: ui/src/main/kotlin/app/aaps/ui/dialogs/WizardDialog.kt
Wenn der Wizard die Carbs aus den arguments lesen soll (sonst öffnet er sich leer), in onViewCreated den Aufruf binding.carbsInput.setParams(...) ergänzen:
val initialCarbs = savedInstanceState?.getDouble("carbs_input")
?: arguments?.getDouble("carbs_input", 0.0)?.takeIf { it > 0.0 }
?: 0.0
binding.carbsInput.setParams(
initialCarbs,
0.0,
maxCarbs.toDouble(),
1.0,
DecimalFormat("0"),
false,
binding.okcancel.ok,
textWatcher
)
Alternativ per patch file:
Eine PatchFile um aaps3.4.2.2, AndroidAPS4 (dev) und Iphone iAPS für CarbCam kompatible zu machen gibt es hier:
https://github.com/zehnBE/aaps3.4.2.2-carbcam-patches/
Anzuwenden mit:
git am pfad/zur/datei\0001-xxxxxxxxxx.patch
Bauen
Wie sonst auch, die App AndroidAPS bauen und auf dem Handy aktualisieren.
Dann kannst du per CarbCam die ermittelten Kohlenhydrate an AAPS an den Boluzwizard senden lassen, spritzen und danach in CarbCam die Daten speichern.
Den AAPS-Package-Namen an die jeweilige Variante anpassen — Stock-info.nightscout.androidaps, .full, .pumpcontrol oder der individuelle Build mit eigener applicationId.
[UPDATE]
Im Repro sind auch die Patchfiles für iPhone Loop, iAPS (da übernimmt es auch fett, eiweiss usw.), trio….:
aaps3.4.2.2-carbcam-patches
To Patch aaps3.4.2.2 that it allowed external carbs directly in BolusWizard from CarbCam: https://CarbCam.app
Details: https://zehn.be/2026/06/01/carbcam-kohlenhydrate-direkt-in-den-aaps-bolus-wizard-uebernehmen
To Patch iAPS that it allowed external carbs directly in BolusWizard from CarbCam: https://github.com/zehnBE/aaps3.4.2.2-carbcam-patches/blob/main/0001-iaps-carbcam-integration.patch
To Patch iphone Loop to allow carbs directly from CarbCam.app: https://github.com/zehnBE/aaps3.4.2.2-carbcam-patches/blob/main/0001-loop-carbcam-integration.patch
To Patch trio that it allowed eternal carbs directly into Boluswizard from CarbCam.app: https://github.com/zehnBE/aaps3.4.2.2-carbcam-patches/blob/main/0001-trio-carbcam-integration.patch
https://github.com/zehnBE/aaps3.4.2.2-carbcam-patches/blob/main/0001-aaps-v4-carbcam-integration.patch