CarbCam – Kohlenhydrate direkt in den AAPS 3.4.x.x und iAPS Bolus-Wizard übernehmen

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:

  1. Whitelist — Nur explizit erlaubte Caller-Packages (z.B. de.be10.carbcam) können den Wizard öffnen. Andere Apps werden vom Launcher kommentarlos abgewiesen.
  2. Range-Check — Carbs außerhalb 1–80 g werden verworfen. Wer mehr braucht, hebt den Wert anschließend im Wizard manuell an.
  3. Kein automatischer Bolus — Der Patch öffnet nur den Wizard. Der Benutzer durchläuft denselben Bestätigungsflow wie bei manueller Eingabe.
  4. 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, AAPS 3.4.2.2 + 3.4.2.6, AAPS V4 (dev), iPhone Loop und Trio:

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",
            "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 aaps 3.4.2.2 / 3.4.2.6, AAPS V4 (dev), iPhone iAPS (main + dev), Trio und iPhone Loop für CarbCam kompatibel 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 Juni 2026]

Im Repo sind auch die Patchfiles für iPhone Loop, iAPS, Trio und AAPS V4:

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://ns.10be.de/blog/2026/06/01/carbcam-kohlenhydrate-direkt-in-den-aaps-bolus-wizard-uebernehmen

 

 

[UPDATE 29.09.2026 — alle Apps neu gebaut, aktueller Stand]

Alle Patchfiles wurden am 29.09.2026 gegen den jeweils aktuellen Upstream-Stand neu erzeugt und gepusht. Zusätzlich ist iAPS jetzt mit Fett/Eiweiß/Ballaststoffe-Support, Loop mit den neuen iOS 27 SDK Fixes und AAPS mit 3.4.2.6 als frischste stable dabei.

Aktuelle Patchfiles (Stand 29.09.2026)

Was ist neu bei iAPS

Die CarbCam-Integration übergibt jetzt neben Kohlenhydraten auch Fett, Eiweiß und Ballaststoffe an den AddCarbs-Dialog:

carbcam-iaps://carbs?value=24&fat=20&protein=19&fiber=3&notes=Pizza&source=carbcam

Fehlende Parameter werden als 0 gewertet. Werte außerhalb 0..80 g werden still ignoriert.

Was ist neu bei Loop

Loop-Patch appliert jetzt gegen LoopKit/Loop dev HEAD c2fddb76 — enthält den Fit five toolbar items at 375pt when linked against the iOS 27 SDK Fix und mehrere Xcode 27 Fixes. Damit ist auch der App-Start-Crash mit NSRangeException auf iPhone Air / iOS 26.5.1 aus den Juni-Builds behoben.

Support-Stand pro App

App KH Fett Eiweiß Fiber Stand
AAPS 3.4.2.2 ✓ – – – neu 29.09.2026
AAPS 3.4.2.6 ✓ – – – neu 29.09.2026
AAPS V4 (dev) ✓ – – – neu 29.09.2026
iAPS main (8.3.4) ✓ ✓ ✓ ✓ neu 29.09.2026
iAPS dev ✓ ✓ ✓ ✓ neu 29.09.2026
Trio 0.8.1 ✓ ✓ ✓ – neuer Patchfile-Name
Trio 1.0.1 ✓ ✓ ✓ – neu 29.09.2026 (neueste stable, 1.608 Commits nach 0.8.1)
Loop 3.14.8 ✓ – – – neu 29.09.2026, iPhone Air Crash behoben

Loop und AAPS haben in ihrer Carb-Entry-UI keine Fett/Eiweiß-Felder — CarbCam kann die URL trotzdem einheitlich mit allen Parametern bauen, die Apps ignorieren was sie nicht kennen.